blob: 2026c1b176babdea1322ecc068a1b24b14eb9011 [file] [log] [blame]
Mårten Kongstadeabc9e92015-12-15 16:40:23 +01001/*
2 * Copyright (C) 2016 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
17package com.android.server.om;
18
19import static android.app.AppGlobals.getPackageManager;
20import static android.content.Intent.ACTION_PACKAGE_ADDED;
21import static android.content.Intent.ACTION_PACKAGE_CHANGED;
22import static android.content.Intent.ACTION_PACKAGE_REMOVED;
23import static android.content.Intent.ACTION_USER_REMOVED;
24import static android.content.pm.PackageManager.SIGNATURE_MATCH;
25
26import android.annotation.NonNull;
27import android.annotation.Nullable;
28import android.app.ActivityManager;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010029import android.app.IActivityManager;
30import android.content.BroadcastReceiver;
31import android.content.Context;
32import android.content.Intent;
33import android.content.IntentFilter;
34import android.content.om.IOverlayManager;
35import android.content.om.OverlayInfo;
36import android.content.pm.IPackageManager;
37import android.content.pm.PackageInfo;
38import android.content.pm.PackageManagerInternal;
39import android.content.pm.UserInfo;
40import android.net.Uri;
41import android.os.Binder;
42import android.os.Environment;
43import android.os.IBinder;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010044import android.os.RemoteException;
45import android.os.ResultReceiver;
46import android.os.ShellCallback;
Adam Lesinskia5ca6242017-03-01 15:45:12 -080047import android.os.SystemProperties;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010048import android.os.UserHandle;
Adam Lesinskia5ca6242017-03-01 15:45:12 -080049import android.text.TextUtils;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010050import android.util.ArrayMap;
Adam Lesinskia5ca6242017-03-01 15:45:12 -080051import android.util.ArraySet;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010052import android.util.AtomicFile;
53import android.util.Slog;
54import android.util.SparseArray;
55
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -080056import com.android.internal.util.ConcurrentUtils;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010057import com.android.server.FgThread;
58import com.android.server.IoThread;
59import com.android.server.LocalServices;
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -080060import com.android.server.SystemServerInitThreadPool;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010061import com.android.server.SystemService;
62import com.android.server.pm.Installer;
63import com.android.server.pm.UserManagerService;
64
65import org.xmlpull.v1.XmlPullParserException;
66
67import java.io.File;
68import java.io.FileDescriptor;
69import java.io.FileInputStream;
70import java.io.FileOutputStream;
71import java.io.IOException;
72import java.io.PrintWriter;
73import java.util.ArrayList;
74import java.util.Collections;
75import java.util.HashMap;
76import java.util.List;
77import java.util.Map;
Adam Lesinskia5ca6242017-03-01 15:45:12 -080078import java.util.Set;
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -080079import java.util.concurrent.Future;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010080import java.util.concurrent.atomic.AtomicBoolean;
81
82/**
83 * Service to manage asset overlays.
84 *
85 * <p>Asset overlays are additional resources that come from apks loaded
86 * alongside the system and app apks. This service, the OverlayManagerService
87 * (OMS), tracks which installed overlays to use and provides methods to change
88 * this. Changes propagate to running applications as part of the Activity
89 * lifecycle. This allows Activities to reread their resources at a well
90 * defined point.</p>
91 *
92 * <p>By itself, the OMS will not change what overlays should be active.
93 * Instead, it is only responsible for making sure that overlays *can* be used
94 * from a technical and security point of view and to activate overlays in
95 * response to external requests. The responsibility to toggle overlays on and
96 * off lies within components that implement different use-cases such as themes
97 * or dynamic customization.</p>
98 *
99 * <p>The OMS receives input from three sources:</p>
100 *
101 * <ul>
102 * <li>Callbacks from the SystemService class, specifically when the
103 * Android framework is booting and when the end user switches Android
104 * users.</li>
105 *
106 * <li>Intents from the PackageManagerService (PMS). Overlays are regular
107 * apks, and whenever a package is installed (or removed, or has a
108 * component enabled or disabled), the PMS broadcasts this as an intent.
109 * When the OMS receives one of these intents, it updates its internal
110 * representation of the available overlays and, if there was a visible
111 * change, triggers an asset refresh in the affected apps.</li>
112 *
113 * <li>External requests via the {@link IOverlayManager AIDL interface}.
114 * The interface allows clients to read information about the currently
115 * available overlays, change whether an overlay should be used or not, and
116 * change the relative order in which overlay packages are loaded.
117 * Read-access is granted if the request targets the same Android user as
118 * the caller runs as, or if the caller holds the
119 * INTERACT_ACROSS_USERS_FULL permission. Write-access is granted if the
120 * caller is granted read-access and additionaly holds the
121 * CHANGE_OVERLAY_PACKAGES permission.</li>
122 * </ul>
123 *
124 * <p>The AIDL interface works with String package names, int user IDs, and
125 * {@link OverlayInfo} objects. OverlayInfo instances are used to track a
126 * specific pair of target and overlay packages and include information such as
127 * the current state of the overlay. OverlayInfo objects are immutable.</p>
128 *
129 * <p>Internally, OverlayInfo objects are maintained by the
130 * OverlayManagerSettings class. The OMS and its helper classes are notified of
131 * changes to the settings by the OverlayManagerSettings.ChangeListener
132 * callback interface. The file /data/system/overlays.xml is used to persist
133 * the settings.</p>
134 *
135 * <p>Creation and deletion of idmap files are handled by the IdmapManager
136 * class.</p>
137 *
138 * <p>The following is an overview of OMS and its related classes. Note how box
139 * (2) does the heavy lifting, box (1) interacts with the Android framework,
140 * and box (3) replaces box (1) during unit testing.</p>
141 *
142 * <pre>
143 * Android framework
144 * | ^
145 * . . . | . . . . | . . . .
146 * . | | .
147 * . AIDL, broadcasts .
148 * . intents | .
149 * . | | . . . . . . . . . . . .
150 * . v | . .
151 * . OverlayManagerService . OverlayManagerTests .
152 * . \ . / .
153 * . (1) \ . / (3) .
154 * . . . . . . . . . . \ . . . / . . . . . . . . .
155 * . \ / .
156 * . (2) \ / .
157 * . OverlayManagerServiceImpl .
158 * . | | .
159 * . | | .
160 * . OverlayManagerSettings IdmapManager .
161 * . .
162 * . . . . . . . . . . . . . . . . . . . . . .
163 * </pre>
164 *
165 * <p>Finally, here is a list of keywords used in the OMS context.</p>
166 *
167 * <ul>
168 * <li><b>target [package]</b> -- A regular apk that may have its resource
169 * pool extended by zero or more overlay packages.</li>
170 *
171 * <li><b>overlay [package]</b> -- An apk that provides additional
172 * resources to another apk.</li>
173 *
174 * <li><b>OMS</b> -- The OverlayManagerService, i.e. this class.</li>
175 *
176 * <li><b>approved</b> -- An overlay is approved if the OMS has verified
177 * that it can be used technically speaking (its target package is
178 * installed, at least one resource name in both packages match, the
179 * idmap was created, etc) and that it is secure to do so. External
180 * clients can not change this state.</li>
181 *
182 * <li><b>not approved</b> -- The opposite of approved.</li>
183 *
184 * <li><b>enabled</b> -- An overlay currently in active use and thus part
185 * of resource lookups. This requires the overlay to be approved. Only
186 * external clients can change this state.</li>
187 *
188 * <li><b>disabled</b> -- The opposite of enabled.</li>
189 *
190 * <li><b>idmap</b> -- A mapping of resource IDs between target and overlay
191 * used during resource lookup. Also the name of the binary that creates
192 * the mapping.</li>
193 * </ul>
194 */
195public final class OverlayManagerService extends SystemService {
196
197 static final String TAG = "OverlayManager";
198
199 static final boolean DEBUG = false;
200
201 static final String PERMISSION_DENIED = "Operation not permitted for user shell";
202
Adam Lesinskia5ca6242017-03-01 15:45:12 -0800203 /**
204 * The system property that specifies the default overlays to apply.
205 * This is a semicolon separated list of package names.
206 *
207 * Ex: com.android.vendor.overlay_one;com.android.vendor.overlay_two
208 */
209 private static final String DEFAULT_OVERLAYS_PROP = "ro.boot.vendor.overlay.theme";
210
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100211 private final Object mLock = new Object();
212
213 private final AtomicFile mSettingsFile;
214
215 private final PackageManagerHelper mPackageManager;
216
217 private final UserManagerService mUserManager;
218
219 private final OverlayManagerSettings mSettings;
220
221 private final OverlayManagerServiceImpl mImpl;
222
223 private final AtomicBoolean mPersistSettingsScheduled = new AtomicBoolean(false);
224
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800225 private Future<?> mInitCompleteSignal;
226
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100227 public OverlayManagerService(@NonNull final Context context,
228 @NonNull final Installer installer) {
229 super(context);
230 mSettingsFile =
231 new AtomicFile(new File(Environment.getDataSystemDirectory(), "overlays.xml"));
232 mPackageManager = new PackageManagerHelper();
233 mUserManager = UserManagerService.getInstance();
234 IdmapManager im = new IdmapManager(installer);
235 mSettings = new OverlayManagerSettings();
Adam Lesinskia5ca6242017-03-01 15:45:12 -0800236 mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
237 getDefaultOverlayPackages());
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800238 mInitCompleteSignal = SystemServerInitThreadPool.get().submit(() -> {
239 final IntentFilter packageFilter = new IntentFilter();
240 packageFilter.addAction(ACTION_PACKAGE_ADDED);
241 packageFilter.addAction(ACTION_PACKAGE_CHANGED);
242 packageFilter.addAction(ACTION_PACKAGE_REMOVED);
243 packageFilter.addDataScheme("package");
244 getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL,
245 packageFilter, null, null);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100246
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800247 final IntentFilter userFilter = new IntentFilter();
248 userFilter.addAction(ACTION_USER_REMOVED);
249 getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL,
250 userFilter, null, null);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100251
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800252 restoreSettings();
253 onSwitchUser(UserHandle.USER_SYSTEM);
254 schedulePersistSettings();
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100255
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800256 mSettings.addChangeListener(new OverlayChangeListener());
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100257
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800258 publishBinderService(Context.OVERLAY_SERVICE, mService);
259 publishLocalService(OverlayManagerService.class, this);
260 }, "Init OverlayManagerService");
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100261 }
262
263 @Override
264 public void onStart() {
265 // Intentionally left empty.
266 }
267
268 @Override
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800269 public void onBootPhase(int phase) {
270 if (phase == PHASE_SYSTEM_SERVICES_READY) {
271 ConcurrentUtils.waitForFutureNoInterrupt(mInitCompleteSignal,
272 "Wait for OverlayManagerService init");
273 mInitCompleteSignal = null;
274 }
275 }
276
277 @Override
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100278 public void onSwitchUser(final int newUserId) {
279 // ensure overlays in the settings are up-to-date, and propagate
280 // any asset changes to the rest of the system
281 final List<String> targets;
282 synchronized (mLock) {
283 targets = mImpl.onSwitchUser(newUserId);
284 }
285 updateAssets(newUserId, targets);
286 }
287
Adam Lesinskia5ca6242017-03-01 15:45:12 -0800288 private static Set<String> getDefaultOverlayPackages() {
289 final String str = SystemProperties.get(DEFAULT_OVERLAYS_PROP);
290 if (TextUtils.isEmpty(str)) {
291 return Collections.emptySet();
292 }
293
294 final ArraySet<String> defaultPackages = new ArraySet<>();
295 for (String packageName : str.split(";")) {
296 if (!TextUtils.isEmpty(packageName)) {
297 defaultPackages.add(packageName);
298 }
299 }
300 return defaultPackages;
301 }
302
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100303 private final class PackageReceiver extends BroadcastReceiver {
304 @Override
305 public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
306 final Uri data = intent.getData();
307 if (data == null) {
308 Slog.e(TAG, "Cannot handle package broadcast with null data");
309 return;
310 }
311 final String packageName = data.getSchemeSpecificPart();
312
313 final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
314
315 final int[] userIds;
316 final int extraUid = intent.getIntExtra(Intent.EXTRA_UID, UserHandle.USER_NULL);
317 if (extraUid == UserHandle.USER_NULL) {
318 userIds = mUserManager.getUserIds();
319 } else {
320 userIds = new int[] { UserHandle.getUserId(extraUid) };
321 }
322
323 switch (intent.getAction()) {
324 case ACTION_PACKAGE_ADDED:
325 if (replacing) {
326 onPackageUpgraded(packageName, userIds);
327 } else {
328 onPackageAdded(packageName, userIds);
329 }
330 break;
331 case ACTION_PACKAGE_CHANGED:
332 onPackageChanged(packageName, userIds);
333 break;
334 case ACTION_PACKAGE_REMOVED:
335 if (replacing) {
336 onPackageUpgrading(packageName, userIds);
337 } else {
338 onPackageRemoved(packageName, userIds);
339 }
340 break;
341 default:
342 // do nothing
343 break;
344 }
345 }
346
347 private void onPackageAdded(@NonNull final String packageName,
348 @NonNull final int[] userIds) {
349 for (final int userId : userIds) {
350 synchronized (mLock) {
351 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId, false);
352 if (pi != null) {
353 mPackageManager.cachePackageInfo(packageName, userId, pi);
354 if (!isOverlayPackage(pi)) {
355 mImpl.onTargetPackageAdded(packageName, userId);
356 } else {
357 mImpl.onOverlayPackageAdded(packageName, userId);
358 }
359 }
360 }
361 }
362 }
363
364 private void onPackageChanged(@NonNull final String packageName,
365 @NonNull final int[] userIds) {
366 for (int userId : userIds) {
367 synchronized (mLock) {
368 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId, false);
369 if (pi != null) {
370 mPackageManager.cachePackageInfo(packageName, userId, pi);
371 if (!isOverlayPackage(pi)) {
372 mImpl.onTargetPackageChanged(packageName, userId);
373 } else {
374 mImpl.onOverlayPackageChanged(packageName, userId);
375 }
376 }
377 }
378 }
379 }
380
381 private void onPackageUpgrading(@NonNull final String packageName,
382 @NonNull final int[] userIds) {
383 for (int userId : userIds) {
384 synchronized (mLock) {
385 mPackageManager.forgetPackageInfo(packageName, userId);
386 final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
387 if (oi == null) {
388 mImpl.onTargetPackageUpgrading(packageName, userId);
389 } else {
390 mImpl.onOverlayPackageUpgrading(packageName, userId);
391 }
392 }
393 }
394 }
395
396 private void onPackageUpgraded(@NonNull final String packageName,
397 @NonNull final int[] userIds) {
398 for (int userId : userIds) {
399 synchronized (mLock) {
400 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId, false);
401 if (pi != null) {
402 mPackageManager.cachePackageInfo(packageName, userId, pi);
403 if (!isOverlayPackage(pi)) {
404 mImpl.onTargetPackageUpgraded(packageName, userId);
405 } else {
406 mImpl.onOverlayPackageUpgraded(packageName, userId);
407 }
408 }
409 }
410 }
411 }
412
413 private void onPackageRemoved(@NonNull final String packageName,
414 @NonNull final int[] userIds) {
415 for (int userId : userIds) {
416 synchronized (mLock) {
417 mPackageManager.forgetPackageInfo(packageName, userId);
418 final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
419 if (oi == null) {
420 mImpl.onTargetPackageRemoved(packageName, userId);
421 } else {
422 mImpl.onOverlayPackageRemoved(packageName, userId);
423 }
424 }
425 }
426 }
427 }
428
429 private final class UserReceiver extends BroadcastReceiver {
430 @Override
431 public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
432 switch (intent.getAction()) {
433 case ACTION_USER_REMOVED:
434 final int userId =
435 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
436 if (userId != UserHandle.USER_NULL) {
437 synchronized (mLock) {
438 mImpl.onUserRemoved(userId);
439 mPackageManager.forgetAllPackageInfos(userId);
440 }
441 }
442 break;
443 default:
444 // do nothing
445 break;
446 }
447 }
448 }
449
450 private final IBinder mService = new IOverlayManager.Stub() {
451 @Override
452 public Map<String, List<OverlayInfo>> getAllOverlays(int userId)
453 throws RemoteException {
454 userId = handleIncomingUser(userId, "getAllOverlays");
455
456 synchronized (mLock) {
457 return mImpl.getOverlaysForUser(userId);
458 }
459 }
460
461 @Override
462 public List<OverlayInfo> getOverlayInfosForTarget(@Nullable final String targetPackageName,
463 int userId) throws RemoteException {
464 userId = handleIncomingUser(userId, "getOverlayInfosForTarget");
465 if (targetPackageName == null) {
466 return Collections.emptyList();
467 }
468
469 synchronized (mLock) {
470 return mImpl.getOverlayInfosForTarget(targetPackageName, userId);
471 }
472 }
473
474 @Override
475 public OverlayInfo getOverlayInfo(@Nullable final String packageName,
476 int userId) throws RemoteException {
477 userId = handleIncomingUser(userId, "getOverlayInfo");
478 if (packageName == null) {
479 return null;
480 }
481
482 synchronized (mLock) {
483 return mImpl.getOverlayInfo(packageName, userId);
484 }
485 }
486
487 @Override
488 public boolean setEnabled(@Nullable final String packageName, final boolean enable,
489 int userId) throws RemoteException {
490 enforceChangeOverlayPackagesPermission("setEnabled");
491 userId = handleIncomingUser(userId, "setEnabled");
492 if (packageName == null) {
493 return false;
494 }
495
496 final long ident = Binder.clearCallingIdentity();
497 try {
498 synchronized (mLock) {
499 return mImpl.setEnabled(packageName, enable, userId);
500 }
501 } finally {
502 Binder.restoreCallingIdentity(ident);
503 }
504 }
505
506 @Override
Jason Monk929ed8d2017-03-07 16:01:20 -0500507 public boolean setEnabledExclusive(@Nullable final String packageName, final boolean enable,
508 int userId) throws RemoteException {
509 enforceChangeOverlayPackagesPermission("setEnabled");
510 userId = handleIncomingUser(userId, "setEnabled");
511 if (packageName == null) {
512 return false;
513 }
514
515 final long ident = Binder.clearCallingIdentity();
516 try {
517 synchronized (mLock) {
518 return mImpl.setEnabledExclusive(packageName, enable, userId);
519 }
520 } finally {
521 Binder.restoreCallingIdentity(ident);
522 }
523 }
524
525 @Override
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100526 public boolean setPriority(@Nullable final String packageName,
527 @Nullable final String parentPackageName, int userId) throws RemoteException {
528 enforceChangeOverlayPackagesPermission("setPriority");
529 userId = handleIncomingUser(userId, "setPriority");
530 if (packageName == null || parentPackageName == null) {
531 return false;
532 }
533
534 final long ident = Binder.clearCallingIdentity();
535 try {
536 synchronized (mLock) {
537 return mImpl.setPriority(packageName, parentPackageName, userId);
538 }
539 } finally {
540 Binder.restoreCallingIdentity(ident);
541 }
542 }
543
544 @Override
545 public boolean setHighestPriority(@Nullable final String packageName, int userId)
546 throws RemoteException {
547 enforceChangeOverlayPackagesPermission("setHighestPriority");
548 userId = handleIncomingUser(userId, "setHighestPriority");
549 if (packageName == null) {
550 return false;
551 }
552
553 final long ident = Binder.clearCallingIdentity();
554 try {
555 synchronized (mLock) {
556 return mImpl.setHighestPriority(packageName, userId);
557 }
558 } finally {
559 Binder.restoreCallingIdentity(ident);
560 }
561 }
562
563 @Override
564 public boolean setLowestPriority(@Nullable final String packageName, int userId)
565 throws RemoteException {
566 enforceChangeOverlayPackagesPermission("setLowestPriority");
567 userId = handleIncomingUser(userId, "setLowestPriority");
568 if (packageName == null) {
569 return false;
570 }
571
572 final long ident = Binder.clearCallingIdentity();
573 try {
574 synchronized (mLock) {
575 return mImpl.setLowestPriority(packageName, userId);
576 }
577 } finally {
578 Binder.restoreCallingIdentity(ident);
579 }
580 }
581
582 @Override
583 public void onShellCommand(@NonNull final FileDescriptor in,
584 @NonNull final FileDescriptor out, @NonNull final FileDescriptor err,
585 @NonNull final String[] args, @NonNull final ShellCallback callback,
586 @NonNull final ResultReceiver resultReceiver) {
587 (new OverlayManagerShellCommand(this)).exec(
588 this, in, out, err, args, callback, resultReceiver);
589 }
590
591 @Override
592 protected void dump(@NonNull final FileDescriptor fd, @NonNull final PrintWriter pw,
593 @NonNull final String[] argv) {
594 enforceDumpPermission("dump");
595
596 final boolean verbose = argv.length > 0 && "--verbose".equals(argv[0]);
597
598 synchronized (mLock) {
599 mImpl.onDump(pw);
600 mPackageManager.dump(pw, verbose);
601 }
602 }
603
604 /**
605 * Ensure that the caller has permission to interact with the given userId.
606 * If the calling user is not the same as the provided user, the caller needs
607 * to hold the INTERACT_ACROSS_USERS_FULL permission (or be system uid or
608 * root).
609 *
610 * @param userId the user to interact with
611 * @param message message for any SecurityException
612 */
613 private int handleIncomingUser(final int userId, @NonNull final String message) {
614 return ActivityManager.handleIncomingUser(Binder.getCallingPid(),
615 Binder.getCallingUid(), userId, false, true, message, null);
616 }
617
618 /**
619 * Enforce that the caller holds the CHANGE_OVERLAY_PACKAGES permission (or is
620 * system or root).
621 *
622 * @param message used as message if SecurityException is thrown
623 * @throws SecurityException if the permission check fails
624 */
625 private void enforceChangeOverlayPackagesPermission(@NonNull final String message) {
626 getContext().enforceCallingOrSelfPermission(
627 android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, message);
628 }
629
630 /**
631 * Enforce that the caller holds the DUMP permission (or is system or root).
632 *
633 * @param message used as message if SecurityException is thrown
634 * @throws SecurityException if the permission check fails
635 */
636 private void enforceDumpPermission(@NonNull final String message) {
637 getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
638 message);
639 }
640 };
641
642 private boolean isOverlayPackage(@NonNull final PackageInfo pi) {
643 return pi != null && pi.overlayTarget != null;
644 }
645
646 private final class OverlayChangeListener implements OverlayManagerSettings.ChangeListener {
647 @Override
648 public void onSettingsChanged() {
649 schedulePersistSettings();
650 }
651
652 @Override
653 public void onOverlayAdded(@NonNull final OverlayInfo oi) {
654 scheduleBroadcast(Intent.ACTION_OVERLAY_ADDED, oi, oi.isEnabled());
655 }
656
657 @Override
658 public void onOverlayRemoved(@NonNull final OverlayInfo oi) {
659 scheduleBroadcast(Intent.ACTION_OVERLAY_REMOVED, oi, oi.isEnabled());
660 }
661
662 @Override
663 public void onOverlayChanged(@NonNull final OverlayInfo oi,
664 @NonNull final OverlayInfo oldOi) {
665 scheduleBroadcast(Intent.ACTION_OVERLAY_CHANGED, oi, oi.isEnabled() != oldOi.isEnabled());
666 }
667
668 @Override
669 public void onOverlayPriorityChanged(@NonNull final OverlayInfo oi) {
670 scheduleBroadcast(Intent.ACTION_OVERLAY_PRIORITY_CHANGED, oi, oi.isEnabled());
671 }
672
673 private void scheduleBroadcast(@NonNull final String action, @NonNull final OverlayInfo oi,
674 final boolean doUpdate) {
675 FgThread.getHandler().post(new BroadcastRunnable(action, oi, doUpdate));
676 }
677
678 private final class BroadcastRunnable implements Runnable {
679 private final String mAction;
680 private final OverlayInfo mOverlayInfo;
681 private final boolean mDoUpdate;
682
683 BroadcastRunnable(@NonNull final String action, @NonNull final OverlayInfo oi,
684 final boolean doUpdate) {
685 mAction = action;
686 mOverlayInfo = oi;
687 mDoUpdate = doUpdate;
688 }
689
690 @Override
691 public void run() {
692 if (mDoUpdate) {
693 updateAssets(mOverlayInfo.userId, mOverlayInfo.targetPackageName);
694 }
695 sendBroadcast(mAction, mOverlayInfo.targetPackageName, mOverlayInfo.packageName,
696 mOverlayInfo.userId);
697 }
698
699 private void sendBroadcast(@NonNull final String action,
700 @NonNull final String targetPackageName, @NonNull final String packageName,
701 final int userId) {
702 final Intent intent = new Intent(action, Uri.fromParts("package",
703 String.format("%s/%s", targetPackageName, packageName), null));
704 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
705 if (DEBUG) {
706 Slog.d(TAG, String.format("send broadcast %s", intent));
707 }
708 try {
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200709 ActivityManager.getService().broadcastIntent(null, intent, null, null, 0,
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100710 null, null, null, android.app.AppOpsManager.OP_NONE, null, false, false,
711 userId);
712 } catch (RemoteException e) {
713 // Intentionally left empty.
714 }
715 }
716
717 }
718 }
719
720 private void updateAssets(final int userId, final String targetPackageName) {
721 final List<String> list = new ArrayList<>();
722 list.add(targetPackageName);
723 updateAssets(userId, list);
724 }
725
726 private void updateAssets(final int userId, List<String> targetPackageNames) {
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200727 final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
728 final boolean updateFrameworkRes = targetPackageNames.contains("android");
729 if (updateFrameworkRes) {
730 targetPackageNames = pm.getTargetPackageNames(userId);
731 }
732
733 final Map<String, List<String>> pendingChanges = new ArrayMap<>(targetPackageNames.size());
734 synchronized (mLock) {
735 final int N = targetPackageNames.size();
736 for (int i = 0; i < N; i++) {
737 final String targetPackageName = targetPackageNames.get(i);
738 pendingChanges.put(targetPackageName,
739 mImpl.getEnabledOverlayPackageNames(targetPackageName, userId));
740 }
741 }
742
743 final int N = targetPackageNames.size();
744 for (int i = 0; i < N; i++) {
745 final String targetPackageName = targetPackageNames.get(i);
746 if (!pm.setEnabledOverlayPackages(
747 userId, targetPackageName, pendingChanges.get(targetPackageName))) {
748 Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
749 targetPackageName, userId));
750 }
751 }
752
753 final IActivityManager am = ActivityManager.getService();
754 try {
755 am.scheduleApplicationInfoChanged(targetPackageNames, userId);
756 } catch (RemoteException e) {
757 // Intentionally left empty.
758 }
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100759 }
760
761 private void schedulePersistSettings() {
762 if (mPersistSettingsScheduled.getAndSet(true)) {
763 return;
764 }
765 IoThread.getHandler().post(new Runnable() {
766 @Override
767 public void run() {
768 mPersistSettingsScheduled.set(false);
769 synchronized (mLock) {
770 FileOutputStream stream = null;
771 try {
772 stream = mSettingsFile.startWrite();
773 mSettings.persist(stream);
774 mSettingsFile.finishWrite(stream);
775 } catch (IOException | XmlPullParserException e) {
776 mSettingsFile.failWrite(stream);
777 Slog.e(TAG, "failed to persist overlay state", e);
778 }
779 }
780 }
781 });
782 }
783
784 private void restoreSettings() {
785 synchronized (mLock) {
786 if (!mSettingsFile.getBaseFile().exists()) {
787 return;
788 }
789 try (final FileInputStream stream = mSettingsFile.openRead()) {
790 mSettings.restore(stream);
791
792 // We might have data for dying users if the device was
793 // restarted before we received USER_REMOVED. Remove data for
794 // users that will not exist after the system is ready.
795
796 final List<UserInfo> deadUsers = getDeadUsers();
797 final int N = deadUsers.size();
798 for (int i = 0; i < N; i++) {
799 final UserInfo deadUser = deadUsers.get(i);
800 final int userId = deadUser.getUserHandle().getIdentifier();
801 mSettings.removeUser(userId);
802 }
803 } catch (IOException | XmlPullParserException e) {
804 Slog.e(TAG, "failed to restore overlay state", e);
805 }
806 }
807 }
808
809 private List<UserInfo> getDeadUsers() {
810 final List<UserInfo> users = mUserManager.getUsers(false);
811 final List<UserInfo> onlyLiveUsers = mUserManager.getUsers(true);
812 users.removeAll(onlyLiveUsers);
813 return users;
814 }
815
816 private static final class PackageManagerHelper implements
817 OverlayManagerServiceImpl.PackageManagerHelper {
818
819 private final IPackageManager mPackageManager;
820 private final PackageManagerInternal mPackageManagerInternal;
821
822 // Use a cache for performance and for consistency within OMS: because
823 // additional PACKAGE_* intents may be delivered while we process an
824 // intent, querying the PackageManagerService for the actual current
825 // state may lead to contradictions within OMS. Better then to lag
826 // behind until all pending intents have been processed.
827 private final SparseArray<HashMap<String, PackageInfo>> mCache = new SparseArray<>();
828
829 PackageManagerHelper() {
830 mPackageManager = getPackageManager();
831 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
832 }
833
834 public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId,
835 final boolean useCache) {
836 if (useCache) {
837 final PackageInfo cachedPi = getCachedPackageInfo(packageName, userId);
838 if (cachedPi != null) {
839 return cachedPi;
840 }
841 }
842 try {
843 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0, userId);
844 if (useCache && pi != null) {
845 cachePackageInfo(packageName, userId, pi);
846 }
847 return pi;
848 } catch (RemoteException e) {
849 // Intentionally left empty.
850 }
851 return null;
852 }
853
854 @Override
855 public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId) {
856 return getPackageInfo(packageName, userId, true);
857 }
858
859 @Override
860 public boolean signaturesMatching(@NonNull final String packageName1,
861 @NonNull final String packageName2, final int userId) {
862 // The package manager does not support different versions of packages
863 // to be installed for different users: ignore userId for now.
864 try {
865 return mPackageManager.checkSignatures(packageName1, packageName2) == SIGNATURE_MATCH;
866 } catch (RemoteException e) {
867 // Intentionally left blank
868 }
869 return false;
870 }
871
872 @Override
873 public List<PackageInfo> getOverlayPackages(final int userId) {
874 return mPackageManagerInternal.getOverlayPackages(userId);
875 }
876
877 public PackageInfo getCachedPackageInfo(@NonNull final String packageName,
878 final int userId) {
879 final HashMap<String, PackageInfo> map = mCache.get(userId);
880 return map == null ? null : map.get(packageName);
881 }
882
883 public void cachePackageInfo(@NonNull final String packageName, final int userId,
884 @NonNull final PackageInfo pi) {
885 HashMap<String, PackageInfo> map = mCache.get(userId);
886 if (map == null) {
887 map = new HashMap<>();
888 mCache.put(userId, map);
889 }
890 map.put(packageName, pi);
891 }
892
893 public void forgetPackageInfo(@NonNull final String packageName, final int userId) {
894 final HashMap<String, PackageInfo> map = mCache.get(userId);
895 if (map == null) {
896 return;
897 }
898 map.remove(packageName);
899 if (map.isEmpty()) {
900 mCache.delete(userId);
901 }
902 }
903
904 public void forgetAllPackageInfos(final int userId) {
905 mCache.delete(userId);
906 }
907
908 private static final String TAB1 = " ";
909 private static final String TAB2 = TAB1 + TAB1;
910
911 public void dump(@NonNull final PrintWriter pw, final boolean verbose) {
912 pw.println("PackageInfo cache");
913
914 if (!verbose) {
915 int count = 0;
916 final int N = mCache.size();
917 for (int i = 0; i < N; i++) {
918 final int userId = mCache.keyAt(i);
919 count += mCache.get(userId).size();
920 }
921 pw.println(TAB1 + count + " package(s)");
922 return;
923 }
924
925 if (mCache.size() == 0) {
926 pw.println(TAB1 + "<empty>");
927 return;
928 }
929
930 final int N = mCache.size();
931 for (int i = 0; i < N; i++) {
932 final int userId = mCache.keyAt(i);
933 pw.println(TAB1 + "User " + userId);
934 final HashMap<String, PackageInfo> map = mCache.get(userId);
935 for (Map.Entry<String, PackageInfo> entry : map.entrySet()) {
936 pw.println(TAB2 + entry.getKey() + ": " + entry.getValue());
937 }
938 }
939 }
940 }
941}