1 /* 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 17 package com.android.server.om; 18 19 import static android.app.AppGlobals.getPackageManager; 20 import static android.content.Intent.ACTION_PACKAGE_ADDED; 21 import static android.content.Intent.ACTION_PACKAGE_CHANGED; 22 import static android.content.Intent.ACTION_PACKAGE_REMOVED; 23 import static android.content.Intent.ACTION_USER_ADDED; 24 import static android.content.Intent.ACTION_USER_REMOVED; 25 import static android.content.pm.PackageManager.SIGNATURE_MATCH; 26 import static android.os.Trace.TRACE_TAG_RRO; 27 import static android.os.Trace.traceBegin; 28 import static android.os.Trace.traceEnd; 29 30 import android.annotation.NonNull; 31 import android.annotation.Nullable; 32 import android.app.ActivityManager; 33 import android.app.IActivityManager; 34 import android.content.BroadcastReceiver; 35 import android.content.Context; 36 import android.content.Intent; 37 import android.content.IntentFilter; 38 import android.content.om.IOverlayManager; 39 import android.content.om.OverlayInfo; 40 import android.content.pm.IPackageManager; 41 import android.content.pm.PackageInfo; 42 import android.content.pm.PackageManagerInternal; 43 import android.content.pm.UserInfo; 44 import android.net.Uri; 45 import android.os.Binder; 46 import android.os.Environment; 47 import android.os.IBinder; 48 import android.os.RemoteException; 49 import android.os.ResultReceiver; 50 import android.os.ShellCallback; 51 import android.os.SystemProperties; 52 import android.os.UserHandle; 53 import android.os.UserManager; 54 import android.text.TextUtils; 55 import android.util.ArrayMap; 56 import android.util.ArraySet; 57 import android.util.AtomicFile; 58 import android.util.Slog; 59 import android.util.SparseArray; 60 61 import com.android.server.FgThread; 62 import com.android.server.IoThread; 63 import com.android.server.LocalServices; 64 import com.android.server.SystemService; 65 import com.android.server.pm.Installer; 66 import com.android.server.pm.UserManagerService; 67 68 import libcore.util.EmptyArray; 69 70 import org.xmlpull.v1.XmlPullParserException; 71 72 import java.io.File; 73 import java.io.FileDescriptor; 74 import java.io.FileInputStream; 75 import java.io.FileOutputStream; 76 import java.io.IOException; 77 import java.io.PrintWriter; 78 import java.util.ArrayList; 79 import java.util.Arrays; 80 import java.util.Collections; 81 import java.util.HashMap; 82 import java.util.List; 83 import java.util.Map; 84 import java.util.concurrent.atomic.AtomicBoolean; 85 86 /** 87 * Service to manage asset overlays. 88 * 89 * <p>Asset overlays are additional resources that come from apks loaded 90 * alongside the system and app apks. This service, the OverlayManagerService 91 * (OMS), tracks which installed overlays to use and provides methods to change 92 * this. Changes propagate to running applications as part of the Activity 93 * lifecycle. This allows Activities to reread their resources at a well 94 * defined point.</p> 95 * 96 * <p>By itself, the OMS will not change what overlays should be active. 97 * Instead, it is only responsible for making sure that overlays *can* be used 98 * from a technical and security point of view and to activate overlays in 99 * response to external requests. The responsibility to toggle overlays on and 100 * off lies within components that implement different use-cases such as themes 101 * or dynamic customization.</p> 102 * 103 * <p>The OMS receives input from three sources:</p> 104 * 105 * <ul> 106 * <li>Callbacks from the SystemService class, specifically when the 107 * Android framework is booting and when the end user switches Android 108 * users.</li> 109 * 110 * <li>Intents from the PackageManagerService (PMS). Overlays are regular 111 * apks, and whenever a package is installed (or removed, or has a 112 * component enabled or disabled), the PMS broadcasts this as an intent. 113 * When the OMS receives one of these intents, it updates its internal 114 * representation of the available overlays and, if there was a visible 115 * change, triggers an asset refresh in the affected apps.</li> 116 * 117 * <li>External requests via the {@link IOverlayManager AIDL interface}. 118 * The interface allows clients to read information about the currently 119 * available overlays, change whether an overlay should be used or not, and 120 * change the relative order in which overlay packages are loaded. 121 * Read-access is granted if the request targets the same Android user as 122 * the caller runs as, or if the caller holds the 123 * INTERACT_ACROSS_USERS_FULL permission. Write-access is granted if the 124 * caller is granted read-access and additionaly holds the 125 * CHANGE_OVERLAY_PACKAGES permission.</li> 126 * </ul> 127 * 128 * <p>The AIDL interface works with String package names, int user IDs, and 129 * {@link OverlayInfo} objects. OverlayInfo instances are used to track a 130 * specific pair of target and overlay packages and include information such as 131 * the current state of the overlay. OverlayInfo objects are immutable.</p> 132 * 133 * <p>Internally, OverlayInfo objects are maintained by the 134 * OverlayManagerSettings class. The OMS and its helper classes are notified of 135 * changes to the settings by the OverlayManagerSettings.ChangeListener 136 * callback interface. The file /data/system/overlays.xml is used to persist 137 * the settings.</p> 138 * 139 * <p>Creation and deletion of idmap files are handled by the IdmapManager 140 * class.</p> 141 * 142 * <p>The following is an overview of OMS and its related classes. Note how box 143 * (2) does the heavy lifting, box (1) interacts with the Android framework, 144 * and box (3) replaces box (1) during unit testing.</p> 145 * 146 * <pre> 147 * Android framework 148 * | ^ 149 * . . . | . . . . | . . . . 150 * . | | . 151 * . AIDL, broadcasts . 152 * . intents | . 153 * . | | . . . . . . . . . . . . 154 * . v | . . 155 * . OverlayManagerService . OverlayManagerTests . 156 * . \ . / . 157 * . (1) \ . / (3) . 158 * . . . . . . . . . . \ . . . / . . . . . . . . . 159 * . \ / . 160 * . (2) \ / . 161 * . OverlayManagerServiceImpl . 162 * . | | . 163 * . | | . 164 * . OverlayManagerSettings IdmapManager . 165 * . . 166 * . . . . . . . . . . . . . . . . . . . . . . 167 * </pre> 168 * 169 * <p>To test the OMS, execute: 170 * <code> 171 * atest FrameworksServicesTests:com.android.server.om # internal tests 172 * atest OverlayDeviceTests OverlayHostTests # public API tests 173 * </code> 174 * </p> 175 * 176 * <p>Finally, here is a list of keywords used in the OMS context.</p> 177 * 178 * <ul> 179 * <li><b>target [package]</b> -- A regular apk that may have its resource 180 * pool extended by zero or more overlay packages.</li> 181 * 182 * <li><b>overlay [package]</b> -- An apk that provides additional 183 * resources to another apk.</li> 184 * 185 * <li><b>OMS</b> -- The OverlayManagerService, i.e. this class.</li> 186 * 187 * <li><b>approved</b> -- An overlay is approved if the OMS has verified 188 * that it can be used technically speaking (its target package is 189 * installed, at least one resource name in both packages match, the 190 * idmap was created, etc) and that it is secure to do so. External 191 * clients can not change this state.</li> 192 * 193 * <li><b>not approved</b> -- The opposite of approved.</li> 194 * 195 * <li><b>enabled</b> -- An overlay currently in active use and thus part 196 * of resource lookups. This requires the overlay to be approved. Only 197 * external clients can change this state.</li> 198 * 199 * <li><b>disabled</b> -- The opposite of enabled.</li> 200 * 201 * <li><b>idmap</b> -- A mapping of resource IDs between target and overlay 202 * used during resource lookup. Also the name of the binary that creates 203 * the mapping.</li> 204 * </ul> 205 */ 206 public final class OverlayManagerService extends SystemService { 207 static final String TAG = "OverlayManager"; 208 209 static final boolean DEBUG = false; 210 211 /** 212 * The system property that specifies the default overlays to apply. 213 * This is a semicolon separated list of package names. 214 * 215 * Ex: com.android.vendor.overlay_one;com.android.vendor.overlay_two 216 */ 217 private static final String DEFAULT_OVERLAYS_PROP = "ro.boot.vendor.overlay.theme"; 218 219 private final Object mLock = new Object(); 220 221 private final AtomicFile mSettingsFile; 222 223 private final PackageManagerHelper mPackageManager; 224 225 private final UserManagerService mUserManager; 226 227 private final OverlayManagerSettings mSettings; 228 229 private final OverlayManagerServiceImpl mImpl; 230 231 private final AtomicBoolean mPersistSettingsScheduled = new AtomicBoolean(false); 232 OverlayManagerService(@onNull final Context context, @NonNull final Installer installer)233 public OverlayManagerService(@NonNull final Context context, 234 @NonNull final Installer installer) { 235 super(context); 236 try { 237 traceBegin(TRACE_TAG_RRO, "OMS#OverlayManagerService"); 238 mSettingsFile = new AtomicFile( 239 new File(Environment.getDataSystemDirectory(), "overlays.xml"), "overlays"); 240 mPackageManager = new PackageManagerHelper(); 241 mUserManager = UserManagerService.getInstance(); 242 IdmapManager im = new IdmapManager(installer, mPackageManager); 243 mSettings = new OverlayManagerSettings(); 244 mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings, 245 getDefaultOverlayPackages(), new OverlayChangeListener()); 246 247 final IntentFilter packageFilter = new IntentFilter(); 248 packageFilter.addAction(ACTION_PACKAGE_ADDED); 249 packageFilter.addAction(ACTION_PACKAGE_CHANGED); 250 packageFilter.addAction(ACTION_PACKAGE_REMOVED); 251 packageFilter.addDataScheme("package"); 252 getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL, 253 packageFilter, null, null); 254 255 final IntentFilter userFilter = new IntentFilter(); 256 userFilter.addAction(ACTION_USER_ADDED); 257 userFilter.addAction(ACTION_USER_REMOVED); 258 getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL, 259 userFilter, null, null); 260 261 restoreSettings(); 262 263 initIfNeeded(); 264 onSwitchUser(UserHandle.USER_SYSTEM); 265 266 publishBinderService(Context.OVERLAY_SERVICE, mService); 267 publishLocalService(OverlayManagerService.class, this); 268 } finally { 269 traceEnd(TRACE_TAG_RRO); 270 } 271 } 272 273 @Override onStart()274 public void onStart() { 275 // Intentionally left empty. 276 } 277 initIfNeeded()278 private void initIfNeeded() { 279 final UserManager um = getContext().getSystemService(UserManager.class); 280 final List<UserInfo> users = um.getUsers(true /*excludeDying*/); 281 synchronized (mLock) { 282 final int userCount = users.size(); 283 for (int i = 0; i < userCount; i++) { 284 final UserInfo userInfo = users.get(i); 285 if (!userInfo.supportsSwitchTo() && userInfo.id != UserHandle.USER_SYSTEM) { 286 // Initialize any users that can't be switched to, as there state would 287 // never be setup in onSwitchUser(). We will switch to the system user right 288 // after this, and its state will be setup there. 289 final List<String> targets = mImpl.updateOverlaysForUser(users.get(i).id); 290 updateOverlayPaths(users.get(i).id, targets); 291 } 292 } 293 } 294 } 295 296 @Override onSwitchUser(final int newUserId)297 public void onSwitchUser(final int newUserId) { 298 try { 299 traceBegin(TRACE_TAG_RRO, "OMS#onSwitchUser " + newUserId); 300 // ensure overlays in the settings are up-to-date, and propagate 301 // any asset changes to the rest of the system 302 synchronized (mLock) { 303 final List<String> targets = mImpl.updateOverlaysForUser(newUserId); 304 updateAssets(newUserId, targets); 305 } 306 schedulePersistSettings(); 307 } finally { 308 traceEnd(TRACE_TAG_RRO); 309 } 310 } 311 getDefaultOverlayPackages()312 private static String[] getDefaultOverlayPackages() { 313 final String str = SystemProperties.get(DEFAULT_OVERLAYS_PROP); 314 if (TextUtils.isEmpty(str)) { 315 return EmptyArray.STRING; 316 } 317 318 final ArraySet<String> defaultPackages = new ArraySet<>(); 319 for (String packageName : str.split(";")) { 320 if (!TextUtils.isEmpty(packageName)) { 321 defaultPackages.add(packageName); 322 } 323 } 324 return defaultPackages.toArray(new String[defaultPackages.size()]); 325 } 326 327 private final class PackageReceiver extends BroadcastReceiver { 328 @Override onReceive(@onNull final Context context, @NonNull final Intent intent)329 public void onReceive(@NonNull final Context context, @NonNull final Intent intent) { 330 final String action = intent.getAction(); 331 if (action == null) { 332 Slog.e(TAG, "Cannot handle package broadcast with null action"); 333 return; 334 } 335 final Uri data = intent.getData(); 336 if (data == null) { 337 Slog.e(TAG, "Cannot handle package broadcast with null data"); 338 return; 339 } 340 final String packageName = data.getSchemeSpecificPart(); 341 342 final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); 343 344 final int[] userIds; 345 final int extraUid = intent.getIntExtra(Intent.EXTRA_UID, UserHandle.USER_NULL); 346 if (extraUid == UserHandle.USER_NULL) { 347 userIds = mUserManager.getUserIds(); 348 } else { 349 userIds = new int[] { UserHandle.getUserId(extraUid) }; 350 } 351 352 switch (action) { 353 case ACTION_PACKAGE_ADDED: 354 if (replacing) { 355 onPackageReplaced(packageName, userIds); 356 } else { 357 onPackageAdded(packageName, userIds); 358 } 359 break; 360 case ACTION_PACKAGE_CHANGED: 361 onPackageChanged(packageName, userIds); 362 break; 363 case ACTION_PACKAGE_REMOVED: 364 if (replacing) { 365 onPackageReplacing(packageName, userIds); 366 } else { 367 onPackageRemoved(packageName, userIds); 368 } 369 break; 370 default: 371 // do nothing 372 break; 373 } 374 } 375 onPackageAdded(@onNull final String packageName, @NonNull final int[] userIds)376 private void onPackageAdded(@NonNull final String packageName, 377 @NonNull final int[] userIds) { 378 try { 379 traceBegin(TRACE_TAG_RRO, "OMS#onPackageAdded " + packageName); 380 for (final int userId : userIds) { 381 synchronized (mLock) { 382 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId, 383 false); 384 if (pi != null && !pi.applicationInfo.isInstantApp()) { 385 mPackageManager.cachePackageInfo(packageName, userId, pi); 386 if (pi.isOverlayPackage()) { 387 mImpl.onOverlayPackageAdded(packageName, userId); 388 } else { 389 mImpl.onTargetPackageAdded(packageName, userId); 390 } 391 } 392 } 393 } 394 } finally { 395 traceEnd(TRACE_TAG_RRO); 396 } 397 } 398 onPackageChanged(@onNull final String packageName, @NonNull final int[] userIds)399 private void onPackageChanged(@NonNull final String packageName, 400 @NonNull final int[] userIds) { 401 try { 402 traceBegin(TRACE_TAG_RRO, "OMS#onPackageChanged " + packageName); 403 for (int userId : userIds) { 404 synchronized (mLock) { 405 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId, 406 false); 407 if (pi != null && pi.applicationInfo.isInstantApp()) { 408 mPackageManager.cachePackageInfo(packageName, userId, pi); 409 if (pi.isOverlayPackage()) { 410 mImpl.onOverlayPackageChanged(packageName, userId); 411 } else { 412 mImpl.onTargetPackageChanged(packageName, userId); 413 } 414 } 415 } 416 } 417 } finally { 418 traceEnd(TRACE_TAG_RRO); 419 } 420 } 421 onPackageReplacing(@onNull final String packageName, @NonNull final int[] userIds)422 private void onPackageReplacing(@NonNull final String packageName, 423 @NonNull final int[] userIds) { 424 try { 425 traceBegin(TRACE_TAG_RRO, "OMS#onPackageReplacing " + packageName); 426 for (int userId : userIds) { 427 synchronized (mLock) { 428 mPackageManager.forgetPackageInfo(packageName, userId); 429 final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId); 430 if (oi != null) { 431 mImpl.onOverlayPackageReplacing(packageName, userId); 432 } 433 } 434 } 435 } finally { 436 traceEnd(TRACE_TAG_RRO); 437 } 438 } 439 onPackageReplaced(@onNull final String packageName, @NonNull final int[] userIds)440 private void onPackageReplaced(@NonNull final String packageName, 441 @NonNull final int[] userIds) { 442 try { 443 traceBegin(TRACE_TAG_RRO, "OMS#onPackageReplaced " + packageName); 444 for (int userId : userIds) { 445 synchronized (mLock) { 446 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId, 447 false); 448 if (pi != null && !pi.applicationInfo.isInstantApp()) { 449 mPackageManager.cachePackageInfo(packageName, userId, pi); 450 if (pi.isOverlayPackage()) { 451 mImpl.onOverlayPackageReplaced(packageName, userId); 452 } else { 453 mImpl.onTargetPackageReplaced(packageName, userId); 454 } 455 } 456 } 457 } 458 } finally { 459 traceEnd(TRACE_TAG_RRO); 460 } 461 } 462 onPackageRemoved(@onNull final String packageName, @NonNull final int[] userIds)463 private void onPackageRemoved(@NonNull final String packageName, 464 @NonNull final int[] userIds) { 465 try { 466 traceBegin(TRACE_TAG_RRO, "OMS#onPackageRemoved " + packageName); 467 for (int userId : userIds) { 468 synchronized (mLock) { 469 mPackageManager.forgetPackageInfo(packageName, userId); 470 final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId); 471 if (oi != null) { 472 mImpl.onOverlayPackageRemoved(packageName, userId); 473 } else { 474 mImpl.onTargetPackageRemoved(packageName, userId); 475 } 476 } 477 } 478 } finally { 479 traceEnd(TRACE_TAG_RRO); 480 } 481 } 482 } 483 484 private final class UserReceiver extends BroadcastReceiver { 485 @Override onReceive(@onNull final Context context, @NonNull final Intent intent)486 public void onReceive(@NonNull final Context context, @NonNull final Intent intent) { 487 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); 488 switch (intent.getAction()) { 489 case ACTION_USER_ADDED: 490 if (userId != UserHandle.USER_NULL) { 491 try { 492 traceBegin(TRACE_TAG_RRO, "OMS ACTION_USER_ADDED"); 493 final ArrayList<String> targets; 494 synchronized (mLock) { 495 targets = mImpl.updateOverlaysForUser(userId); 496 } 497 updateOverlayPaths(userId, targets); 498 } finally { 499 traceEnd(TRACE_TAG_RRO); 500 } 501 } 502 break; 503 504 case ACTION_USER_REMOVED: 505 if (userId != UserHandle.USER_NULL) { 506 try { 507 traceBegin(TRACE_TAG_RRO, "OMS ACTION_USER_REMOVED"); 508 synchronized (mLock) { 509 mImpl.onUserRemoved(userId); 510 mPackageManager.forgetAllPackageInfos(userId); 511 } 512 } finally { 513 traceEnd(TRACE_TAG_RRO); 514 } 515 } 516 break; 517 default: 518 // do nothing 519 break; 520 } 521 } 522 } 523 524 private final IBinder mService = new IOverlayManager.Stub() { 525 @Override 526 public Map<String, List<OverlayInfo>> getAllOverlays(int userId) throws RemoteException { 527 try { 528 traceBegin(TRACE_TAG_RRO, "OMS#getAllOverlays " + userId); 529 userId = handleIncomingUser(userId, "getAllOverlays"); 530 531 synchronized (mLock) { 532 return mImpl.getOverlaysForUser(userId); 533 } 534 } finally { 535 traceEnd(TRACE_TAG_RRO); 536 } 537 } 538 539 @Override 540 public List<OverlayInfo> getOverlayInfosForTarget(@Nullable final String targetPackageName, 541 int userId) throws RemoteException { 542 try { 543 traceBegin(TRACE_TAG_RRO, "OMS#getOverlayInfosForTarget " + targetPackageName); 544 userId = handleIncomingUser(userId, "getOverlayInfosForTarget"); 545 if (targetPackageName == null) { 546 return Collections.emptyList(); 547 } 548 549 synchronized (mLock) { 550 return mImpl.getOverlayInfosForTarget(targetPackageName, userId); 551 } 552 } finally { 553 traceEnd(TRACE_TAG_RRO); 554 } 555 } 556 557 @Override 558 public OverlayInfo getOverlayInfo(@Nullable final String packageName, 559 int userId) throws RemoteException { 560 try { 561 traceBegin(TRACE_TAG_RRO, "OMS#getOverlayInfo " + packageName); 562 userId = handleIncomingUser(userId, "getOverlayInfo"); 563 if (packageName == null) { 564 return null; 565 } 566 567 synchronized (mLock) { 568 return mImpl.getOverlayInfo(packageName, userId); 569 } 570 } finally { 571 traceEnd(TRACE_TAG_RRO); 572 } 573 } 574 575 @Override 576 public boolean setEnabled(@Nullable final String packageName, final boolean enable, 577 int userId) throws RemoteException { 578 try { 579 traceBegin(TRACE_TAG_RRO, "OMS#setEnabled " + packageName + " " + enable); 580 enforceChangeOverlayPackagesPermission("setEnabled"); 581 userId = handleIncomingUser(userId, "setEnabled"); 582 if (packageName == null) { 583 return false; 584 } 585 586 final long ident = Binder.clearCallingIdentity(); 587 try { 588 synchronized (mLock) { 589 return mImpl.setEnabled(packageName, enable, userId); 590 } 591 } finally { 592 Binder.restoreCallingIdentity(ident); 593 } 594 } finally { 595 traceEnd(TRACE_TAG_RRO); 596 } 597 } 598 599 @Override 600 public boolean setEnabledExclusive(@Nullable final String packageName, final boolean enable, 601 int userId) throws RemoteException { 602 try { 603 traceBegin(TRACE_TAG_RRO, "OMS#setEnabledExclusive " + packageName + " " + enable); 604 enforceChangeOverlayPackagesPermission("setEnabledExclusive"); 605 userId = handleIncomingUser(userId, "setEnabledExclusive"); 606 if (packageName == null || !enable) { 607 return false; 608 } 609 610 final long ident = Binder.clearCallingIdentity(); 611 try { 612 synchronized (mLock) { 613 return mImpl.setEnabledExclusive(packageName, false /* withinCategory */, 614 userId); 615 } 616 } finally { 617 Binder.restoreCallingIdentity(ident); 618 } 619 } finally { 620 traceEnd(TRACE_TAG_RRO); 621 } 622 } 623 624 @Override 625 public boolean setEnabledExclusiveInCategory(@Nullable String packageName, int userId) 626 throws RemoteException { 627 try { 628 traceBegin(TRACE_TAG_RRO, "OMS#setEnabledExclusiveInCategory " + packageName); 629 enforceChangeOverlayPackagesPermission("setEnabledExclusiveInCategory"); 630 userId = handleIncomingUser(userId, "setEnabledExclusiveInCategory"); 631 if (packageName == null) { 632 return false; 633 } 634 635 final long ident = Binder.clearCallingIdentity(); 636 try { 637 synchronized (mLock) { 638 return mImpl.setEnabledExclusive(packageName, true /* withinCategory */, 639 userId); 640 } 641 } finally { 642 Binder.restoreCallingIdentity(ident); 643 } 644 } finally { 645 traceEnd(TRACE_TAG_RRO); 646 } 647 } 648 649 @Override 650 public boolean setPriority(@Nullable final String packageName, 651 @Nullable final String parentPackageName, int userId) throws RemoteException { 652 try { 653 traceBegin(TRACE_TAG_RRO, "OMS#setPriority " + packageName + " " 654 + parentPackageName); 655 enforceChangeOverlayPackagesPermission("setPriority"); 656 userId = handleIncomingUser(userId, "setPriority"); 657 if (packageName == null || parentPackageName == null) { 658 return false; 659 } 660 661 final long ident = Binder.clearCallingIdentity(); 662 try { 663 synchronized (mLock) { 664 return mImpl.setPriority(packageName, parentPackageName, userId); 665 } 666 } finally { 667 Binder.restoreCallingIdentity(ident); 668 } 669 } finally { 670 traceEnd(TRACE_TAG_RRO); 671 } 672 } 673 674 @Override 675 public boolean setHighestPriority(@Nullable final String packageName, int userId) 676 throws RemoteException { 677 try { 678 traceBegin(TRACE_TAG_RRO, "OMS#setHighestPriority " + packageName); 679 enforceChangeOverlayPackagesPermission("setHighestPriority"); 680 userId = handleIncomingUser(userId, "setHighestPriority"); 681 if (packageName == null) { 682 return false; 683 } 684 685 final long ident = Binder.clearCallingIdentity(); 686 try { 687 synchronized (mLock) { 688 return mImpl.setHighestPriority(packageName, userId); 689 } 690 } finally { 691 Binder.restoreCallingIdentity(ident); 692 } 693 } finally { 694 traceEnd(TRACE_TAG_RRO); 695 } 696 } 697 698 @Override 699 public boolean setLowestPriority(@Nullable final String packageName, int userId) 700 throws RemoteException { 701 try { 702 traceBegin(TRACE_TAG_RRO, "OMS#setLowestPriority " + packageName); 703 enforceChangeOverlayPackagesPermission("setLowestPriority"); 704 userId = handleIncomingUser(userId, "setLowestPriority"); 705 if (packageName == null) { 706 return false; 707 } 708 709 final long ident = Binder.clearCallingIdentity(); 710 try { 711 synchronized (mLock) { 712 return mImpl.setLowestPriority(packageName, userId); 713 } 714 } finally { 715 Binder.restoreCallingIdentity(ident); 716 } 717 } finally { 718 traceEnd(TRACE_TAG_RRO); 719 } 720 } 721 722 @Override 723 public String[] getDefaultOverlayPackages() throws RemoteException { 724 try { 725 traceBegin(TRACE_TAG_RRO, "OMS#getDefaultOverlayPackages"); 726 getContext().enforceCallingOrSelfPermission( 727 android.Manifest.permission.MODIFY_THEME_OVERLAY, null); 728 729 final long ident = Binder.clearCallingIdentity(); 730 try { 731 synchronized (mLock) { 732 return mImpl.getDefaultOverlayPackages(); 733 } 734 } finally { 735 Binder.restoreCallingIdentity(ident); 736 } 737 } finally { 738 traceEnd(TRACE_TAG_RRO); 739 } 740 } 741 742 @Override 743 public void onShellCommand(@NonNull final FileDescriptor in, 744 @NonNull final FileDescriptor out, @NonNull final FileDescriptor err, 745 @NonNull final String[] args, @NonNull final ShellCallback callback, 746 @NonNull final ResultReceiver resultReceiver) { 747 (new OverlayManagerShellCommand(this)).exec( 748 this, in, out, err, args, callback, resultReceiver); 749 } 750 751 @Override 752 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 753 final DumpState dumpState = new DumpState(); 754 dumpState.setUserId(UserHandle.getUserId(Binder.getCallingUid())); 755 756 int opti = 0; 757 while (opti < args.length) { 758 final String opt = args[opti]; 759 if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') { 760 break; 761 } 762 opti++; 763 764 if ("-h".equals(opt)) { 765 pw.println("dump [-h] [--verbose] [--user USER_ID] [[FIELD] PACKAGE]"); 766 pw.println(" Print debugging information about the overlay manager."); 767 pw.println(" With optional parameter PACKAGE, limit output to the specified"); 768 pw.println(" package. With optional parameter FIELD, limit output to"); 769 pw.println(" the value of that SettingsItem field. Field names are"); 770 pw.println(" case insensitive and out.println the m prefix can be omitted,"); 771 pw.println(" so the following are equivalent: mState, mstate, State, state."); 772 return; 773 } else if ("--user".equals(opt)) { 774 opti++; 775 if (opti >= args.length) { 776 pw.println("Error: user missing argument"); 777 return; 778 } 779 try { 780 dumpState.setUserId(Integer.parseInt(args[opti])); 781 } catch (NumberFormatException e) { 782 pw.println("Error: user argument is not a number: " + args[opti]); 783 return; 784 } 785 } else if ("--verbose".equals(opt)) { 786 dumpState.setVerbose(true); 787 } else { 788 pw.println("Unknown argument: " + opt + "; use -h for help"); 789 } 790 } 791 if (opti < args.length) { 792 final String arg = args[opti]; 793 opti++; 794 switch (arg) { 795 case "packagename": 796 case "userid": 797 case "targetpackagename": 798 case "targetoverlayablename": 799 case "basecodepath": 800 case "state": 801 case "isenabled": 802 case "isstatic": 803 case "priority": 804 case "category": 805 dumpState.setField(arg); 806 break; 807 default: 808 dumpState.setPackageName(arg); 809 break; 810 } 811 } 812 if (dumpState.getPackageName() == null && opti < args.length) { 813 dumpState.setPackageName(args[opti]); 814 opti++; 815 } 816 817 enforceDumpPermission("dump"); 818 synchronized (mLock) { 819 mImpl.dump(pw, dumpState); 820 if (dumpState.getPackageName() == null) { 821 mPackageManager.dump(pw, dumpState); 822 } 823 } 824 } 825 826 /** 827 * Ensure that the caller has permission to interact with the given userId. 828 * If the calling user is not the same as the provided user, the caller needs 829 * to hold the INTERACT_ACROSS_USERS_FULL permission (or be system uid or 830 * root). 831 * 832 * @param userId the user to interact with 833 * @param message message for any SecurityException 834 */ 835 private int handleIncomingUser(final int userId, @NonNull final String message) { 836 return ActivityManager.handleIncomingUser(Binder.getCallingPid(), 837 Binder.getCallingUid(), userId, false, true, message, null); 838 } 839 840 /** 841 * Enforce that the caller holds the CHANGE_OVERLAY_PACKAGES permission (or is 842 * system or root). 843 * 844 * @param message used as message if SecurityException is thrown 845 * @throws SecurityException if the permission check fails 846 */ 847 private void enforceChangeOverlayPackagesPermission(@NonNull final String message) { 848 getContext().enforceCallingOrSelfPermission( 849 android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, message); 850 } 851 852 /** 853 * Enforce that the caller holds the DUMP permission (or is system or root). 854 * 855 * @param message used as message if SecurityException is thrown 856 * @throws SecurityException if the permission check fails 857 */ 858 private void enforceDumpPermission(@NonNull final String message) { 859 getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, message); 860 } 861 }; 862 863 private final class OverlayChangeListener 864 implements OverlayManagerServiceImpl.OverlayChangeListener { 865 @Override onOverlaysChanged(@onNull final String targetPackageName, final int userId)866 public void onOverlaysChanged(@NonNull final String targetPackageName, final int userId) { 867 schedulePersistSettings(); 868 FgThread.getHandler().post(() -> { 869 updateAssets(userId, targetPackageName); 870 871 final Intent intent = new Intent(Intent.ACTION_OVERLAY_CHANGED, 872 Uri.fromParts("package", targetPackageName, null)); 873 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 874 875 if (DEBUG) { 876 Slog.d(TAG, "send broadcast " + intent); 877 } 878 879 try { 880 ActivityManager.getService().broadcastIntent(null, intent, null, null, 0, 881 null, null, null, android.app.AppOpsManager.OP_NONE, null, false, false, 882 userId); 883 } catch (RemoteException e) { 884 // Intentionally left empty. 885 } 886 }); 887 } 888 } 889 890 /** 891 * Updates the target packages' set of enabled overlays in PackageManager. 892 */ updateOverlayPaths(int userId, List<String> targetPackageNames)893 private void updateOverlayPaths(int userId, List<String> targetPackageNames) { 894 try { 895 traceBegin(TRACE_TAG_RRO, "OMS#updateOverlayPaths " + targetPackageNames); 896 if (DEBUG) { 897 Slog.d(TAG, "Updating overlay assets"); 898 } 899 final PackageManagerInternal pm = 900 LocalServices.getService(PackageManagerInternal.class); 901 final boolean updateFrameworkRes = targetPackageNames.contains("android"); 902 if (updateFrameworkRes) { 903 targetPackageNames = pm.getTargetPackageNames(userId); 904 } 905 906 final Map<String, List<String>> pendingChanges = 907 new ArrayMap<>(targetPackageNames.size()); 908 synchronized (mLock) { 909 final List<String> frameworkOverlays = 910 mImpl.getEnabledOverlayPackageNames("android", userId); 911 final int n = targetPackageNames.size(); 912 for (int i = 0; i < n; i++) { 913 final String targetPackageName = targetPackageNames.get(i); 914 List<String> list = new ArrayList<>(); 915 if (!"android".equals(targetPackageName)) { 916 list.addAll(frameworkOverlays); 917 } 918 list.addAll(mImpl.getEnabledOverlayPackageNames(targetPackageName, userId)); 919 pendingChanges.put(targetPackageName, list); 920 } 921 } 922 923 final int n = targetPackageNames.size(); 924 for (int i = 0; i < n; i++) { 925 final String targetPackageName = targetPackageNames.get(i); 926 if (DEBUG) { 927 Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=[" 928 + TextUtils.join(",", pendingChanges.get(targetPackageName)) 929 + "] userId=" + userId); 930 } 931 932 if (!pm.setEnabledOverlayPackages( 933 userId, targetPackageName, pendingChanges.get(targetPackageName))) { 934 Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d", 935 targetPackageName, userId)); 936 } 937 } 938 } finally { 939 traceEnd(TRACE_TAG_RRO); 940 } 941 } 942 updateAssets(final int userId, final String targetPackageName)943 private void updateAssets(final int userId, final String targetPackageName) { 944 updateAssets(userId, Collections.singletonList(targetPackageName)); 945 } 946 updateAssets(final int userId, List<String> targetPackageNames)947 private void updateAssets(final int userId, List<String> targetPackageNames) { 948 updateOverlayPaths(userId, targetPackageNames); 949 final IActivityManager am = ActivityManager.getService(); 950 try { 951 am.scheduleApplicationInfoChanged(targetPackageNames, userId); 952 } catch (RemoteException e) { 953 // Intentionally left empty. 954 } 955 } 956 schedulePersistSettings()957 private void schedulePersistSettings() { 958 if (mPersistSettingsScheduled.getAndSet(true)) { 959 return; 960 } 961 IoThread.getHandler().post(() -> { 962 mPersistSettingsScheduled.set(false); 963 if (DEBUG) { 964 Slog.d(TAG, "Writing overlay settings"); 965 } 966 synchronized (mLock) { 967 FileOutputStream stream = null; 968 try { 969 stream = mSettingsFile.startWrite(); 970 mSettings.persist(stream); 971 mSettingsFile.finishWrite(stream); 972 } catch (IOException | XmlPullParserException e) { 973 mSettingsFile.failWrite(stream); 974 Slog.e(TAG, "failed to persist overlay state", e); 975 } 976 } 977 }); 978 } 979 restoreSettings()980 private void restoreSettings() { 981 try { 982 traceBegin(TRACE_TAG_RRO, "OMS#restoreSettings"); 983 synchronized (mLock) { 984 if (!mSettingsFile.getBaseFile().exists()) { 985 return; 986 } 987 try (FileInputStream stream = mSettingsFile.openRead()) { 988 mSettings.restore(stream); 989 990 // We might have data for dying users if the device was 991 // restarted before we received USER_REMOVED. Remove data for 992 // users that will not exist after the system is ready. 993 994 final List<UserInfo> liveUsers = mUserManager.getUsers(true /*excludeDying*/); 995 final int[] liveUserIds = new int[liveUsers.size()]; 996 for (int i = 0; i < liveUsers.size(); i++) { 997 liveUserIds[i] = liveUsers.get(i).getUserHandle().getIdentifier(); 998 } 999 Arrays.sort(liveUserIds); 1000 1001 for (int userId : mSettings.getUsers()) { 1002 if (Arrays.binarySearch(liveUserIds, userId) < 0) { 1003 mSettings.removeUser(userId); 1004 } 1005 } 1006 } catch (IOException | XmlPullParserException e) { 1007 Slog.e(TAG, "failed to restore overlay state", e); 1008 } 1009 } 1010 } finally { 1011 traceEnd(TRACE_TAG_RRO); 1012 } 1013 } 1014 1015 private static final class PackageManagerHelper implements 1016 OverlayManagerServiceImpl.PackageManagerHelper { 1017 1018 private final IPackageManager mPackageManager; 1019 private final PackageManagerInternal mPackageManagerInternal; 1020 1021 // Use a cache for performance and for consistency within OMS: because 1022 // additional PACKAGE_* intents may be delivered while we process an 1023 // intent, querying the PackageManagerService for the actual current 1024 // state may lead to contradictions within OMS. Better then to lag 1025 // behind until all pending intents have been processed. 1026 private final SparseArray<HashMap<String, PackageInfo>> mCache = new SparseArray<>(); 1027 PackageManagerHelper()1028 PackageManagerHelper() { 1029 mPackageManager = getPackageManager(); 1030 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); 1031 } 1032 getPackageInfo(@onNull final String packageName, final int userId, final boolean useCache)1033 public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId, 1034 final boolean useCache) { 1035 if (useCache) { 1036 final PackageInfo cachedPi = getCachedPackageInfo(packageName, userId); 1037 if (cachedPi != null) { 1038 return cachedPi; 1039 } 1040 } 1041 try { 1042 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0, userId); 1043 if (useCache && pi != null) { 1044 cachePackageInfo(packageName, userId, pi); 1045 } 1046 return pi; 1047 } catch (RemoteException e) { 1048 // Intentionally left empty. 1049 } 1050 return null; 1051 } 1052 1053 @Override getPackageInfo(@onNull final String packageName, final int userId)1054 public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId) { 1055 return getPackageInfo(packageName, userId, true); 1056 } 1057 1058 @Override signaturesMatching(@onNull final String packageName1, @NonNull final String packageName2, final int userId)1059 public boolean signaturesMatching(@NonNull final String packageName1, 1060 @NonNull final String packageName2, final int userId) { 1061 // The package manager does not support different versions of packages 1062 // to be installed for different users: ignore userId for now. 1063 try { 1064 return mPackageManager.checkSignatures( 1065 packageName1, packageName2) == SIGNATURE_MATCH; 1066 } catch (RemoteException e) { 1067 // Intentionally left blank 1068 } 1069 return false; 1070 } 1071 1072 @Override getOverlayPackages(final int userId)1073 public List<PackageInfo> getOverlayPackages(final int userId) { 1074 return mPackageManagerInternal.getOverlayPackages(userId); 1075 } 1076 getCachedPackageInfo(@onNull final String packageName, final int userId)1077 public PackageInfo getCachedPackageInfo(@NonNull final String packageName, 1078 final int userId) { 1079 final HashMap<String, PackageInfo> map = mCache.get(userId); 1080 return map == null ? null : map.get(packageName); 1081 } 1082 cachePackageInfo(@onNull final String packageName, final int userId, @NonNull final PackageInfo pi)1083 public void cachePackageInfo(@NonNull final String packageName, final int userId, 1084 @NonNull final PackageInfo pi) { 1085 HashMap<String, PackageInfo> map = mCache.get(userId); 1086 if (map == null) { 1087 map = new HashMap<>(); 1088 mCache.put(userId, map); 1089 } 1090 map.put(packageName, pi); 1091 } 1092 forgetPackageInfo(@onNull final String packageName, final int userId)1093 public void forgetPackageInfo(@NonNull final String packageName, final int userId) { 1094 final HashMap<String, PackageInfo> map = mCache.get(userId); 1095 if (map == null) { 1096 return; 1097 } 1098 map.remove(packageName); 1099 if (map.isEmpty()) { 1100 mCache.delete(userId); 1101 } 1102 } 1103 forgetAllPackageInfos(final int userId)1104 public void forgetAllPackageInfos(final int userId) { 1105 mCache.delete(userId); 1106 } 1107 1108 private static final String TAB1 = " "; 1109 private static final String TAB2 = TAB1 + TAB1; 1110 dump(@onNull final PrintWriter pw, @NonNull DumpState dumpState)1111 public void dump(@NonNull final PrintWriter pw, @NonNull DumpState dumpState) { 1112 pw.println("PackageInfo cache"); 1113 1114 if (!dumpState.isVerbose()) { 1115 int count = 0; 1116 final int n = mCache.size(); 1117 for (int i = 0; i < n; i++) { 1118 final int userId = mCache.keyAt(i); 1119 count += mCache.get(userId).size(); 1120 } 1121 pw.println(TAB1 + count + " package(s)"); 1122 return; 1123 } 1124 1125 if (mCache.size() == 0) { 1126 pw.println(TAB1 + "<empty>"); 1127 return; 1128 } 1129 1130 final int n = mCache.size(); 1131 for (int i = 0; i < n; i++) { 1132 final int userId = mCache.keyAt(i); 1133 pw.println(TAB1 + "User " + userId); 1134 final HashMap<String, PackageInfo> map = mCache.get(userId); 1135 for (Map.Entry<String, PackageInfo> entry : map.entrySet()) { 1136 pw.println(TAB2 + entry.getKey() + ": " + entry.getValue()); 1137 } 1138 } 1139 } 1140 } 1141 } 1142