blob: a7f114655dcb4ad2b73dd00b1368d3f6f3bfff53 [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;
Adam Lesinskiada8deb2017-05-12 13:50:42 -070023import static android.content.Intent.ACTION_USER_ADDED;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010024import static android.content.Intent.ACTION_USER_REMOVED;
25import static android.content.pm.PackageManager.SIGNATURE_MATCH;
26
27import android.annotation.NonNull;
28import android.annotation.Nullable;
29import android.app.ActivityManager;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010030import android.app.IActivityManager;
31import android.content.BroadcastReceiver;
32import android.content.Context;
33import android.content.Intent;
34import android.content.IntentFilter;
35import android.content.om.IOverlayManager;
36import android.content.om.OverlayInfo;
37import android.content.pm.IPackageManager;
38import android.content.pm.PackageInfo;
39import android.content.pm.PackageManagerInternal;
40import android.content.pm.UserInfo;
41import android.net.Uri;
42import android.os.Binder;
43import android.os.Environment;
44import android.os.IBinder;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010045import android.os.RemoteException;
46import android.os.ResultReceiver;
47import android.os.ShellCallback;
Adam Lesinskia5ca6242017-03-01 15:45:12 -080048import android.os.SystemProperties;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010049import android.os.UserHandle;
Adam Lesinskiada8deb2017-05-12 13:50:42 -070050import android.os.UserManager;
Adam Lesinskia5ca6242017-03-01 15:45:12 -080051import android.text.TextUtils;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010052import android.util.ArrayMap;
Adam Lesinskia5ca6242017-03-01 15:45:12 -080053import android.util.ArraySet;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010054import android.util.AtomicFile;
55import android.util.Slog;
56import android.util.SparseArray;
57
58import com.android.server.FgThread;
59import com.android.server.IoThread;
60import com.android.server.LocalServices;
61import com.android.server.SystemService;
62import com.android.server.pm.Installer;
63import com.android.server.pm.UserManagerService;
64
Adam Lesinski7b031812018-02-22 13:32:53 -080065import libcore.util.EmptyArray;
66
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010067import org.xmlpull.v1.XmlPullParserException;
68
69import java.io.File;
70import java.io.FileDescriptor;
71import java.io.FileInputStream;
72import java.io.FileOutputStream;
73import java.io.IOException;
74import java.io.PrintWriter;
75import java.util.ArrayList;
Adam Lesinskid11c5512017-04-11 12:01:10 -070076import java.util.Arrays;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010077import java.util.Collections;
78import java.util.HashMap;
79import java.util.List;
80import java.util.Map;
81import java.util.concurrent.atomic.AtomicBoolean;
82
83/**
84 * Service to manage asset overlays.
85 *
86 * <p>Asset overlays are additional resources that come from apks loaded
87 * alongside the system and app apks. This service, the OverlayManagerService
88 * (OMS), tracks which installed overlays to use and provides methods to change
89 * this. Changes propagate to running applications as part of the Activity
90 * lifecycle. This allows Activities to reread their resources at a well
91 * defined point.</p>
92 *
93 * <p>By itself, the OMS will not change what overlays should be active.
94 * Instead, it is only responsible for making sure that overlays *can* be used
95 * from a technical and security point of view and to activate overlays in
96 * response to external requests. The responsibility to toggle overlays on and
97 * off lies within components that implement different use-cases such as themes
98 * or dynamic customization.</p>
99 *
100 * <p>The OMS receives input from three sources:</p>
101 *
102 * <ul>
103 * <li>Callbacks from the SystemService class, specifically when the
104 * Android framework is booting and when the end user switches Android
105 * users.</li>
106 *
107 * <li>Intents from the PackageManagerService (PMS). Overlays are regular
108 * apks, and whenever a package is installed (or removed, or has a
109 * component enabled or disabled), the PMS broadcasts this as an intent.
110 * When the OMS receives one of these intents, it updates its internal
111 * representation of the available overlays and, if there was a visible
112 * change, triggers an asset refresh in the affected apps.</li>
113 *
114 * <li>External requests via the {@link IOverlayManager AIDL interface}.
115 * The interface allows clients to read information about the currently
116 * available overlays, change whether an overlay should be used or not, and
117 * change the relative order in which overlay packages are loaded.
118 * Read-access is granted if the request targets the same Android user as
119 * the caller runs as, or if the caller holds the
120 * INTERACT_ACROSS_USERS_FULL permission. Write-access is granted if the
121 * caller is granted read-access and additionaly holds the
122 * CHANGE_OVERLAY_PACKAGES permission.</li>
123 * </ul>
124 *
125 * <p>The AIDL interface works with String package names, int user IDs, and
126 * {@link OverlayInfo} objects. OverlayInfo instances are used to track a
127 * specific pair of target and overlay packages and include information such as
128 * the current state of the overlay. OverlayInfo objects are immutable.</p>
129 *
130 * <p>Internally, OverlayInfo objects are maintained by the
131 * OverlayManagerSettings class. The OMS and its helper classes are notified of
132 * changes to the settings by the OverlayManagerSettings.ChangeListener
133 * callback interface. The file /data/system/overlays.xml is used to persist
134 * the settings.</p>
135 *
136 * <p>Creation and deletion of idmap files are handled by the IdmapManager
137 * class.</p>
138 *
139 * <p>The following is an overview of OMS and its related classes. Note how box
140 * (2) does the heavy lifting, box (1) interacts with the Android framework,
141 * and box (3) replaces box (1) during unit testing.</p>
142 *
143 * <pre>
144 * Android framework
145 * | ^
146 * . . . | . . . . | . . . .
147 * . | | .
148 * . AIDL, broadcasts .
149 * . intents | .
150 * . | | . . . . . . . . . . . .
151 * . v | . .
152 * . OverlayManagerService . OverlayManagerTests .
153 * . \ . / .
154 * . (1) \ . / (3) .
155 * . . . . . . . . . . \ . . . / . . . . . . . . .
156 * . \ / .
157 * . (2) \ / .
158 * . OverlayManagerServiceImpl .
159 * . | | .
160 * . | | .
161 * . OverlayManagerSettings IdmapManager .
162 * . .
163 * . . . . . . . . . . . . . . . . . . . . . .
164 * </pre>
165 *
166 * <p>Finally, here is a list of keywords used in the OMS context.</p>
167 *
168 * <ul>
169 * <li><b>target [package]</b> -- A regular apk that may have its resource
170 * pool extended by zero or more overlay packages.</li>
171 *
172 * <li><b>overlay [package]</b> -- An apk that provides additional
173 * resources to another apk.</li>
174 *
175 * <li><b>OMS</b> -- The OverlayManagerService, i.e. this class.</li>
176 *
177 * <li><b>approved</b> -- An overlay is approved if the OMS has verified
178 * that it can be used technically speaking (its target package is
179 * installed, at least one resource name in both packages match, the
180 * idmap was created, etc) and that it is secure to do so. External
181 * clients can not change this state.</li>
182 *
183 * <li><b>not approved</b> -- The opposite of approved.</li>
184 *
185 * <li><b>enabled</b> -- An overlay currently in active use and thus part
186 * of resource lookups. This requires the overlay to be approved. Only
187 * external clients can change this state.</li>
188 *
189 * <li><b>disabled</b> -- The opposite of enabled.</li>
190 *
191 * <li><b>idmap</b> -- A mapping of resource IDs between target and overlay
192 * used during resource lookup. Also the name of the binary that creates
193 * the mapping.</li>
194 * </ul>
195 */
196public final class OverlayManagerService extends SystemService {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100197 static final String TAG = "OverlayManager";
198
199 static final boolean DEBUG = false;
200
Adam Lesinskia5ca6242017-03-01 15:45:12 -0800201 /**
202 * The system property that specifies the default overlays to apply.
203 * This is a semicolon separated list of package names.
204 *
205 * Ex: com.android.vendor.overlay_one;com.android.vendor.overlay_two
206 */
207 private static final String DEFAULT_OVERLAYS_PROP = "ro.boot.vendor.overlay.theme";
208
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100209 private final Object mLock = new Object();
210
211 private final AtomicFile mSettingsFile;
212
213 private final PackageManagerHelper mPackageManager;
214
215 private final UserManagerService mUserManager;
216
217 private final OverlayManagerSettings mSettings;
218
219 private final OverlayManagerServiceImpl mImpl;
220
221 private final AtomicBoolean mPersistSettingsScheduled = new AtomicBoolean(false);
222
223 public OverlayManagerService(@NonNull final Context context,
224 @NonNull final Installer installer) {
225 super(context);
Mårten Kongstad38988342018-12-04 10:28:01 +0100226 mSettingsFile = new AtomicFile(
227 new File(Environment.getDataSystemDirectory(), "overlays.xml"), "overlays");
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100228 mPackageManager = new PackageManagerHelper();
229 mUserManager = UserManagerService.getInstance();
230 IdmapManager im = new IdmapManager(installer);
231 mSettings = new OverlayManagerSettings();
Adam Lesinskia5ca6242017-03-01 15:45:12 -0800232 mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
Adam Lesinskic745f422017-04-05 16:31:30 -0700233 getDefaultOverlayPackages(), new OverlayChangeListener());
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100234
Mårten Kongstadcd78e0f2018-05-23 10:41:35 +0200235 final IntentFilter packageFilter = new IntentFilter();
236 packageFilter.addAction(ACTION_PACKAGE_ADDED);
237 packageFilter.addAction(ACTION_PACKAGE_CHANGED);
238 packageFilter.addAction(ACTION_PACKAGE_REMOVED);
239 packageFilter.addDataScheme("package");
240 getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL,
241 packageFilter, null, null);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100242
Mårten Kongstadcd78e0f2018-05-23 10:41:35 +0200243 final IntentFilter userFilter = new IntentFilter();
244 userFilter.addAction(ACTION_USER_ADDED);
245 userFilter.addAction(ACTION_USER_REMOVED);
246 getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL,
247 userFilter, null, null);
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700248
Mårten Kongstadcd78e0f2018-05-23 10:41:35 +0200249 restoreSettings();
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100250
Mårten Kongstadcd78e0f2018-05-23 10:41:35 +0200251 initIfNeeded();
252 onSwitchUser(UserHandle.USER_SYSTEM);
253
254 publishBinderService(Context.OVERLAY_SERVICE, mService);
255 publishLocalService(OverlayManagerService.class, this);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100256 }
257
258 @Override
259 public void onStart() {
260 // Intentionally left empty.
261 }
262
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700263 private void initIfNeeded() {
264 final UserManager um = getContext().getSystemService(UserManager.class);
265 final List<UserInfo> users = um.getUsers(true /*excludeDying*/);
266 synchronized (mLock) {
267 final int userCount = users.size();
268 for (int i = 0; i < userCount; i++) {
269 final UserInfo userInfo = users.get(i);
270 if (!userInfo.supportsSwitchTo() && userInfo.id != UserHandle.USER_SYSTEM) {
271 // Initialize any users that can't be switched to, as there state would
272 // never be setup in onSwitchUser(). We will switch to the system user right
273 // after this, and its state will be setup there.
274 final List<String> targets = mImpl.updateOverlaysForUser(users.get(i).id);
275 updateOverlayPaths(users.get(i).id, targets);
276 }
277 }
278 }
279 }
280
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800281 @Override
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100282 public void onSwitchUser(final int newUserId) {
283 // ensure overlays in the settings are up-to-date, and propagate
284 // any asset changes to the rest of the system
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100285 synchronized (mLock) {
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700286 final List<String> targets = mImpl.updateOverlaysForUser(newUserId);
287 updateAssets(newUserId, targets);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100288 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700289 schedulePersistSettings();
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100290 }
291
Adam Lesinski7b031812018-02-22 13:32:53 -0800292 private static String[] getDefaultOverlayPackages() {
Adam Lesinskia5ca6242017-03-01 15:45:12 -0800293 final String str = SystemProperties.get(DEFAULT_OVERLAYS_PROP);
294 if (TextUtils.isEmpty(str)) {
Adam Lesinski7b031812018-02-22 13:32:53 -0800295 return EmptyArray.STRING;
Adam Lesinskia5ca6242017-03-01 15:45:12 -0800296 }
297
298 final ArraySet<String> defaultPackages = new ArraySet<>();
299 for (String packageName : str.split(";")) {
300 if (!TextUtils.isEmpty(packageName)) {
301 defaultPackages.add(packageName);
302 }
303 }
Adam Lesinski7b031812018-02-22 13:32:53 -0800304 return defaultPackages.toArray(new String[defaultPackages.size()]);
Adam Lesinskia5ca6242017-03-01 15:45:12 -0800305 }
306
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100307 private final class PackageReceiver extends BroadcastReceiver {
308 @Override
309 public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
310 final Uri data = intent.getData();
311 if (data == null) {
312 Slog.e(TAG, "Cannot handle package broadcast with null data");
313 return;
314 }
315 final String packageName = data.getSchemeSpecificPart();
316
317 final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
318
319 final int[] userIds;
320 final int extraUid = intent.getIntExtra(Intent.EXTRA_UID, UserHandle.USER_NULL);
321 if (extraUid == UserHandle.USER_NULL) {
322 userIds = mUserManager.getUserIds();
323 } else {
324 userIds = new int[] { UserHandle.getUserId(extraUid) };
325 }
326
327 switch (intent.getAction()) {
328 case ACTION_PACKAGE_ADDED:
329 if (replacing) {
330 onPackageUpgraded(packageName, userIds);
331 } else {
332 onPackageAdded(packageName, userIds);
333 }
334 break;
335 case ACTION_PACKAGE_CHANGED:
336 onPackageChanged(packageName, userIds);
337 break;
338 case ACTION_PACKAGE_REMOVED:
339 if (replacing) {
340 onPackageUpgrading(packageName, userIds);
341 } else {
342 onPackageRemoved(packageName, userIds);
343 }
344 break;
345 default:
346 // do nothing
347 break;
348 }
349 }
350
351 private void onPackageAdded(@NonNull final String packageName,
352 @NonNull final int[] userIds) {
353 for (final int userId : userIds) {
354 synchronized (mLock) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700355 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
356 false);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100357 if (pi != null) {
358 mPackageManager.cachePackageInfo(packageName, userId, pi);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800359 if (pi.isOverlayPackage()) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100360 mImpl.onOverlayPackageAdded(packageName, userId);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800361 } else {
362 mImpl.onTargetPackageAdded(packageName, userId);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100363 }
364 }
365 }
366 }
367 }
368
369 private void onPackageChanged(@NonNull final String packageName,
370 @NonNull final int[] userIds) {
371 for (int userId : userIds) {
372 synchronized (mLock) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700373 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
374 false);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100375 if (pi != null) {
376 mPackageManager.cachePackageInfo(packageName, userId, pi);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800377 if (pi.isOverlayPackage()) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100378 mImpl.onOverlayPackageChanged(packageName, userId);
Ryan Mitchelld41d0db2018-05-09 09:01:12 -0700379 } else {
380 mImpl.onTargetPackageChanged(packageName, userId);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100381 }
382 }
383 }
384 }
385 }
386
387 private void onPackageUpgrading(@NonNull final String packageName,
388 @NonNull final int[] userIds) {
389 for (int userId : userIds) {
390 synchronized (mLock) {
391 mPackageManager.forgetPackageInfo(packageName, userId);
392 final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800393 if (oi != null) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100394 mImpl.onOverlayPackageUpgrading(packageName, userId);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800395 } else {
396 mImpl.onTargetPackageUpgrading(packageName, userId);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100397 }
398 }
399 }
400 }
401
402 private void onPackageUpgraded(@NonNull final String packageName,
403 @NonNull final int[] userIds) {
404 for (int userId : userIds) {
405 synchronized (mLock) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700406 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
407 false);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100408 if (pi != null) {
409 mPackageManager.cachePackageInfo(packageName, userId, pi);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800410 if (pi.isOverlayPackage()) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100411 mImpl.onOverlayPackageUpgraded(packageName, userId);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800412 } else {
413 mImpl.onTargetPackageUpgraded(packageName, userId);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100414 }
415 }
416 }
417 }
418 }
419
420 private void onPackageRemoved(@NonNull final String packageName,
421 @NonNull final int[] userIds) {
422 for (int userId : userIds) {
423 synchronized (mLock) {
424 mPackageManager.forgetPackageInfo(packageName, userId);
425 final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800426 if (oi != null) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100427 mImpl.onOverlayPackageRemoved(packageName, userId);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800428 } else {
429 mImpl.onTargetPackageRemoved(packageName, userId);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100430 }
431 }
432 }
433 }
434 }
435
436 private final class UserReceiver extends BroadcastReceiver {
437 @Override
438 public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700439 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100440 switch (intent.getAction()) {
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700441 case ACTION_USER_ADDED:
442 if (userId != UserHandle.USER_NULL) {
443 final ArrayList<String> targets;
444 synchronized (mLock) {
445 targets = mImpl.updateOverlaysForUser(userId);
446 }
447 updateOverlayPaths(userId, targets);
448 }
449 break;
450
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100451 case ACTION_USER_REMOVED:
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100452 if (userId != UserHandle.USER_NULL) {
453 synchronized (mLock) {
454 mImpl.onUserRemoved(userId);
455 mPackageManager.forgetAllPackageInfos(userId);
456 }
457 }
458 break;
459 default:
460 // do nothing
461 break;
462 }
463 }
464 }
465
466 private final IBinder mService = new IOverlayManager.Stub() {
467 @Override
Adam Lesinskic745f422017-04-05 16:31:30 -0700468 public Map<String, List<OverlayInfo>> getAllOverlays(int userId) throws RemoteException {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100469 userId = handleIncomingUser(userId, "getAllOverlays");
470
471 synchronized (mLock) {
472 return mImpl.getOverlaysForUser(userId);
473 }
474 }
475
476 @Override
477 public List<OverlayInfo> getOverlayInfosForTarget(@Nullable final String targetPackageName,
478 int userId) throws RemoteException {
479 userId = handleIncomingUser(userId, "getOverlayInfosForTarget");
480 if (targetPackageName == null) {
481 return Collections.emptyList();
482 }
483
484 synchronized (mLock) {
485 return mImpl.getOverlayInfosForTarget(targetPackageName, userId);
486 }
487 }
488
489 @Override
490 public OverlayInfo getOverlayInfo(@Nullable final String packageName,
491 int userId) throws RemoteException {
492 userId = handleIncomingUser(userId, "getOverlayInfo");
493 if (packageName == null) {
494 return null;
495 }
496
497 synchronized (mLock) {
498 return mImpl.getOverlayInfo(packageName, userId);
499 }
500 }
501
502 @Override
503 public boolean setEnabled(@Nullable final String packageName, final boolean enable,
504 int userId) throws RemoteException {
505 enforceChangeOverlayPackagesPermission("setEnabled");
506 userId = handleIncomingUser(userId, "setEnabled");
507 if (packageName == null) {
508 return false;
509 }
510
511 final long ident = Binder.clearCallingIdentity();
512 try {
513 synchronized (mLock) {
514 return mImpl.setEnabled(packageName, enable, userId);
515 }
516 } finally {
517 Binder.restoreCallingIdentity(ident);
518 }
519 }
520
521 @Override
Jason Monk929ed8d2017-03-07 16:01:20 -0500522 public boolean setEnabledExclusive(@Nullable final String packageName, final boolean enable,
523 int userId) throws RemoteException {
Mårten Kongstadd7191552018-06-08 08:51:13 +0200524 enforceChangeOverlayPackagesPermission("setEnabledExclusive");
525 userId = handleIncomingUser(userId, "setEnabledExclusive");
Adam Lesinskic745f422017-04-05 16:31:30 -0700526 if (packageName == null || !enable) {
Jason Monk929ed8d2017-03-07 16:01:20 -0500527 return false;
528 }
529
530 final long ident = Binder.clearCallingIdentity();
531 try {
532 synchronized (mLock) {
Adrian Roosc84df772018-01-19 21:20:22 +0100533 return mImpl.setEnabledExclusive(packageName, false /* withinCategory */,
534 userId);
535 }
536 } finally {
537 Binder.restoreCallingIdentity(ident);
538 }
539 }
540
541 @Override
542 public boolean setEnabledExclusiveInCategory(@Nullable String packageName, int userId)
543 throws RemoteException {
Mårten Kongstadd7191552018-06-08 08:51:13 +0200544 enforceChangeOverlayPackagesPermission("setEnabledExclusiveInCategory");
545 userId = handleIncomingUser(userId, "setEnabledExclusiveInCategory");
Adrian Roosc84df772018-01-19 21:20:22 +0100546 if (packageName == null) {
547 return false;
548 }
549
550 final long ident = Binder.clearCallingIdentity();
551 try {
552 synchronized (mLock) {
553 return mImpl.setEnabledExclusive(packageName, true /* withinCategory */,
554 userId);
Jason Monk929ed8d2017-03-07 16:01:20 -0500555 }
556 } finally {
557 Binder.restoreCallingIdentity(ident);
558 }
559 }
560
561 @Override
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100562 public boolean setPriority(@Nullable final String packageName,
563 @Nullable final String parentPackageName, int userId) throws RemoteException {
564 enforceChangeOverlayPackagesPermission("setPriority");
565 userId = handleIncomingUser(userId, "setPriority");
566 if (packageName == null || parentPackageName == null) {
567 return false;
568 }
569
570 final long ident = Binder.clearCallingIdentity();
571 try {
572 synchronized (mLock) {
573 return mImpl.setPriority(packageName, parentPackageName, userId);
574 }
575 } finally {
576 Binder.restoreCallingIdentity(ident);
577 }
578 }
579
580 @Override
581 public boolean setHighestPriority(@Nullable final String packageName, int userId)
582 throws RemoteException {
583 enforceChangeOverlayPackagesPermission("setHighestPriority");
584 userId = handleIncomingUser(userId, "setHighestPriority");
585 if (packageName == null) {
586 return false;
587 }
588
589 final long ident = Binder.clearCallingIdentity();
590 try {
591 synchronized (mLock) {
592 return mImpl.setHighestPriority(packageName, userId);
593 }
594 } finally {
595 Binder.restoreCallingIdentity(ident);
596 }
597 }
598
599 @Override
600 public boolean setLowestPriority(@Nullable final String packageName, int userId)
601 throws RemoteException {
602 enforceChangeOverlayPackagesPermission("setLowestPriority");
603 userId = handleIncomingUser(userId, "setLowestPriority");
604 if (packageName == null) {
605 return false;
606 }
607
608 final long ident = Binder.clearCallingIdentity();
609 try {
610 synchronized (mLock) {
611 return mImpl.setLowestPriority(packageName, userId);
612 }
613 } finally {
614 Binder.restoreCallingIdentity(ident);
615 }
616 }
617
618 @Override
619 public void onShellCommand(@NonNull final FileDescriptor in,
620 @NonNull final FileDescriptor out, @NonNull final FileDescriptor err,
621 @NonNull final String[] args, @NonNull final ShellCallback callback,
622 @NonNull final ResultReceiver resultReceiver) {
623 (new OverlayManagerShellCommand(this)).exec(
624 this, in, out, err, args, callback, resultReceiver);
625 }
626
627 @Override
628 protected void dump(@NonNull final FileDescriptor fd, @NonNull final PrintWriter pw,
629 @NonNull final String[] argv) {
630 enforceDumpPermission("dump");
631
632 final boolean verbose = argv.length > 0 && "--verbose".equals(argv[0]);
633
634 synchronized (mLock) {
635 mImpl.onDump(pw);
636 mPackageManager.dump(pw, verbose);
637 }
638 }
639
640 /**
641 * Ensure that the caller has permission to interact with the given userId.
642 * If the calling user is not the same as the provided user, the caller needs
643 * to hold the INTERACT_ACROSS_USERS_FULL permission (or be system uid or
644 * root).
645 *
646 * @param userId the user to interact with
647 * @param message message for any SecurityException
648 */
649 private int handleIncomingUser(final int userId, @NonNull final String message) {
650 return ActivityManager.handleIncomingUser(Binder.getCallingPid(),
651 Binder.getCallingUid(), userId, false, true, message, null);
652 }
653
654 /**
655 * Enforce that the caller holds the CHANGE_OVERLAY_PACKAGES permission (or is
656 * system or root).
657 *
658 * @param message used as message if SecurityException is thrown
659 * @throws SecurityException if the permission check fails
660 */
661 private void enforceChangeOverlayPackagesPermission(@NonNull final String message) {
Mårten Kongstadf28bec42017-11-16 13:07:30 +0100662 getContext().enforceCallingPermission(
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100663 android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, message);
664 }
665
666 /**
667 * Enforce that the caller holds the DUMP permission (or is system or root).
668 *
669 * @param message used as message if SecurityException is thrown
670 * @throws SecurityException if the permission check fails
671 */
672 private void enforceDumpPermission(@NonNull final String message) {
Mårten Kongstadf28bec42017-11-16 13:07:30 +0100673 getContext().enforceCallingPermission(android.Manifest.permission.DUMP, message);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100674 }
675 };
676
Adam Lesinskic745f422017-04-05 16:31:30 -0700677 private final class OverlayChangeListener
678 implements OverlayManagerServiceImpl.OverlayChangeListener {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100679 @Override
Mårten Kongstad497945c2018-04-27 09:56:13 +0200680 public void onOverlaysChanged(@NonNull final String targetPackageName, final int userId) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100681 schedulePersistSettings();
Adam Lesinskic745f422017-04-05 16:31:30 -0700682 FgThread.getHandler().post(() -> {
Mårten Kongstad497945c2018-04-27 09:56:13 +0200683 updateAssets(userId, targetPackageName);
684
685 final Intent intent = new Intent(Intent.ACTION_OVERLAY_CHANGED,
686 Uri.fromParts("package", targetPackageName, null));
687 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
688
689 if (DEBUG) {
690 Slog.d(TAG, "send broadcast " + intent);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100691 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700692
Mårten Kongstad497945c2018-04-27 09:56:13 +0200693 try {
694 ActivityManager.getService().broadcastIntent(null, intent, null, null, 0,
695 null, null, null, android.app.AppOpsManager.OP_NONE, null, false, false,
696 userId);
697 } catch (RemoteException e) {
698 // Intentionally left empty.
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100699 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700700 });
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100701 }
702 }
703
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700704 /**
705 * Updates the target packages' set of enabled overlays in PackageManager.
706 */
707 private void updateOverlayPaths(int userId, List<String> targetPackageNames) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700708 if (DEBUG) {
709 Slog.d(TAG, "Updating overlay assets");
710 }
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200711 final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
712 final boolean updateFrameworkRes = targetPackageNames.contains("android");
713 if (updateFrameworkRes) {
714 targetPackageNames = pm.getTargetPackageNames(userId);
715 }
716
717 final Map<String, List<String>> pendingChanges = new ArrayMap<>(targetPackageNames.size());
718 synchronized (mLock) {
Todd Kennedy560830c2017-06-16 13:55:13 -0700719 final List<String> frameworkOverlays =
Mårten Kongstad38988342018-12-04 10:28:01 +0100720 mImpl.getEnabledOverlayPackageNames("android", userId);
721 final int n = targetPackageNames.size();
722 for (int i = 0; i < n; i++) {
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200723 final String targetPackageName = targetPackageNames.get(i);
Todd Kennedy560830c2017-06-16 13:55:13 -0700724 List<String> list = new ArrayList<>();
725 if (!"android".equals(targetPackageName)) {
726 list.addAll(frameworkOverlays);
727 }
728 list.addAll(mImpl.getEnabledOverlayPackageNames(targetPackageName, userId));
729 pendingChanges.put(targetPackageName, list);
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200730 }
731 }
732
Mårten Kongstad38988342018-12-04 10:28:01 +0100733 final int n = targetPackageNames.size();
734 for (int i = 0; i < n; i++) {
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200735 final String targetPackageName = targetPackageNames.get(i);
Adam Lesinskic745f422017-04-05 16:31:30 -0700736 if (DEBUG) {
737 Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=["
738 + TextUtils.join(",", pendingChanges.get(targetPackageName))
739 + "] userId=" + userId);
740 }
741
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200742 if (!pm.setEnabledOverlayPackages(
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700743 userId, targetPackageName, pendingChanges.get(targetPackageName))) {
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200744 Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700745 targetPackageName, userId));
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200746 }
747 }
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700748 }
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200749
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700750 private void updateAssets(final int userId, final String targetPackageName) {
751 updateAssets(userId, Collections.singletonList(targetPackageName));
752 }
753
754 private void updateAssets(final int userId, List<String> targetPackageNames) {
755 updateOverlayPaths(userId, targetPackageNames);
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200756 final IActivityManager am = ActivityManager.getService();
757 try {
758 am.scheduleApplicationInfoChanged(targetPackageNames, userId);
759 } catch (RemoteException e) {
760 // Intentionally left empty.
761 }
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100762 }
763
764 private void schedulePersistSettings() {
765 if (mPersistSettingsScheduled.getAndSet(true)) {
766 return;
767 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700768 IoThread.getHandler().post(() -> {
769 mPersistSettingsScheduled.set(false);
770 if (DEBUG) {
771 Slog.d(TAG, "Writing overlay settings");
772 }
773 synchronized (mLock) {
774 FileOutputStream stream = null;
775 try {
776 stream = mSettingsFile.startWrite();
777 mSettings.persist(stream);
778 mSettingsFile.finishWrite(stream);
779 } catch (IOException | XmlPullParserException e) {
780 mSettingsFile.failWrite(stream);
781 Slog.e(TAG, "failed to persist overlay state", e);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100782 }
783 }
784 });
785 }
786
787 private void restoreSettings() {
788 synchronized (mLock) {
789 if (!mSettingsFile.getBaseFile().exists()) {
790 return;
791 }
Mårten Kongstad38988342018-12-04 10:28:01 +0100792 try (FileInputStream stream = mSettingsFile.openRead()) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100793 mSettings.restore(stream);
794
795 // We might have data for dying users if the device was
796 // restarted before we received USER_REMOVED. Remove data for
797 // users that will not exist after the system is ready.
798
Adam Lesinskid11c5512017-04-11 12:01:10 -0700799 final List<UserInfo> liveUsers = mUserManager.getUsers(true /*excludeDying*/);
800 final int[] liveUserIds = new int[liveUsers.size()];
801 for (int i = 0; i < liveUsers.size(); i++) {
802 liveUserIds[i] = liveUsers.get(i).getUserHandle().getIdentifier();
803 }
804 Arrays.sort(liveUserIds);
805
806 for (int userId : mSettings.getUsers()) {
807 if (Arrays.binarySearch(liveUserIds, userId) < 0) {
808 mSettings.removeUser(userId);
809 }
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100810 }
811 } catch (IOException | XmlPullParserException e) {
812 Slog.e(TAG, "failed to restore overlay state", e);
813 }
814 }
815 }
816
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100817 private static final class PackageManagerHelper implements
818 OverlayManagerServiceImpl.PackageManagerHelper {
819
820 private final IPackageManager mPackageManager;
821 private final PackageManagerInternal mPackageManagerInternal;
822
823 // Use a cache for performance and for consistency within OMS: because
824 // additional PACKAGE_* intents may be delivered while we process an
825 // intent, querying the PackageManagerService for the actual current
826 // state may lead to contradictions within OMS. Better then to lag
827 // behind until all pending intents have been processed.
828 private final SparseArray<HashMap<String, PackageInfo>> mCache = new SparseArray<>();
829
830 PackageManagerHelper() {
831 mPackageManager = getPackageManager();
832 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
833 }
834
835 public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId,
836 final boolean useCache) {
837 if (useCache) {
838 final PackageInfo cachedPi = getCachedPackageInfo(packageName, userId);
839 if (cachedPi != null) {
840 return cachedPi;
841 }
842 }
843 try {
844 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0, userId);
845 if (useCache && pi != null) {
846 cachePackageInfo(packageName, userId, pi);
847 }
848 return pi;
849 } catch (RemoteException e) {
850 // Intentionally left empty.
851 }
852 return null;
853 }
854
855 @Override
856 public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId) {
857 return getPackageInfo(packageName, userId, true);
858 }
859
860 @Override
861 public boolean signaturesMatching(@NonNull final String packageName1,
862 @NonNull final String packageName2, final int userId) {
863 // The package manager does not support different versions of packages
864 // to be installed for different users: ignore userId for now.
865 try {
Adam Lesinskic745f422017-04-05 16:31:30 -0700866 return mPackageManager.checkSignatures(
867 packageName1, packageName2) == SIGNATURE_MATCH;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100868 } catch (RemoteException e) {
869 // Intentionally left blank
870 }
871 return false;
872 }
873
874 @Override
875 public List<PackageInfo> getOverlayPackages(final int userId) {
876 return mPackageManagerInternal.getOverlayPackages(userId);
877 }
878
879 public PackageInfo getCachedPackageInfo(@NonNull final String packageName,
880 final int userId) {
881 final HashMap<String, PackageInfo> map = mCache.get(userId);
882 return map == null ? null : map.get(packageName);
883 }
884
885 public void cachePackageInfo(@NonNull final String packageName, final int userId,
886 @NonNull final PackageInfo pi) {
887 HashMap<String, PackageInfo> map = mCache.get(userId);
888 if (map == null) {
889 map = new HashMap<>();
890 mCache.put(userId, map);
891 }
892 map.put(packageName, pi);
893 }
894
895 public void forgetPackageInfo(@NonNull final String packageName, final int userId) {
896 final HashMap<String, PackageInfo> map = mCache.get(userId);
897 if (map == null) {
898 return;
899 }
900 map.remove(packageName);
901 if (map.isEmpty()) {
902 mCache.delete(userId);
903 }
904 }
905
906 public void forgetAllPackageInfos(final int userId) {
907 mCache.delete(userId);
908 }
909
910 private static final String TAB1 = " ";
911 private static final String TAB2 = TAB1 + TAB1;
912
913 public void dump(@NonNull final PrintWriter pw, final boolean verbose) {
914 pw.println("PackageInfo cache");
915
916 if (!verbose) {
917 int count = 0;
Mårten Kongstad38988342018-12-04 10:28:01 +0100918 final int n = mCache.size();
919 for (int i = 0; i < n; i++) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100920 final int userId = mCache.keyAt(i);
921 count += mCache.get(userId).size();
922 }
923 pw.println(TAB1 + count + " package(s)");
924 return;
925 }
926
927 if (mCache.size() == 0) {
928 pw.println(TAB1 + "<empty>");
929 return;
930 }
931
Mårten Kongstad38988342018-12-04 10:28:01 +0100932 final int n = mCache.size();
933 for (int i = 0; i < n; i++) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100934 final int userId = mCache.keyAt(i);
935 pw.println(TAB1 + "User " + userId);
936 final HashMap<String, PackageInfo> map = mCache.get(userId);
937 for (Map.Entry<String, PackageInfo> entry : map.entrySet()) {
938 pw.println(TAB2 + entry.getKey() + ": " + entry.getValue());
939 }
940 }
941 }
942 }
943}