blob: 0147d7e4451fea7e7d844b1773e4cdabd22902d0 [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;
Adrian Roos9ee5dff2018-08-22 20:19:49 +020025import static android.content.pm.PackageManager.GET_SHARED_LIBRARY_FILES;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010026import static android.content.pm.PackageManager.SIGNATURE_MATCH;
27
28import android.annotation.NonNull;
29import android.annotation.Nullable;
30import android.app.ActivityManager;
Adrian Roos9ee5dff2018-08-22 20:19:49 +020031import android.app.ActivityThread;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010032import android.app.IActivityManager;
33import android.content.BroadcastReceiver;
34import android.content.Context;
35import android.content.Intent;
36import android.content.IntentFilter;
37import android.content.om.IOverlayManager;
38import android.content.om.OverlayInfo;
Adrian Roos9ee5dff2018-08-22 20:19:49 +020039import android.content.pm.ApplicationInfo;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010040import android.content.pm.IPackageManager;
41import android.content.pm.PackageInfo;
42import android.content.pm.PackageManagerInternal;
43import android.content.pm.UserInfo;
44import android.net.Uri;
45import android.os.Binder;
46import android.os.Environment;
47import android.os.IBinder;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010048import android.os.RemoteException;
49import android.os.ResultReceiver;
50import android.os.ShellCallback;
Adam Lesinskia5ca6242017-03-01 15:45:12 -080051import android.os.SystemProperties;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010052import android.os.UserHandle;
Adam Lesinskiada8deb2017-05-12 13:50:42 -070053import android.os.UserManager;
Adam Lesinskia5ca6242017-03-01 15:45:12 -080054import android.text.TextUtils;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010055import android.util.ArrayMap;
Adam Lesinskia5ca6242017-03-01 15:45:12 -080056import android.util.ArraySet;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010057import android.util.AtomicFile;
58import android.util.Slog;
59import android.util.SparseArray;
60
61import com.android.server.FgThread;
62import com.android.server.IoThread;
63import com.android.server.LocalServices;
64import com.android.server.SystemService;
65import com.android.server.pm.Installer;
66import com.android.server.pm.UserManagerService;
67
Adam Lesinski7b031812018-02-22 13:32:53 -080068import libcore.util.EmptyArray;
69
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010070import org.xmlpull.v1.XmlPullParserException;
71
72import java.io.File;
73import java.io.FileDescriptor;
74import java.io.FileInputStream;
75import java.io.FileOutputStream;
76import java.io.IOException;
77import java.io.PrintWriter;
78import java.util.ArrayList;
Adam Lesinskid11c5512017-04-11 12:01:10 -070079import java.util.Arrays;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010080import java.util.Collections;
81import java.util.HashMap;
82import java.util.List;
83import java.util.Map;
84import 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>Finally, here is a list of keywords used in the OMS context.</p>
170 *
171 * <ul>
172 * <li><b>target [package]</b> -- A regular apk that may have its resource
173 * pool extended by zero or more overlay packages.</li>
174 *
175 * <li><b>overlay [package]</b> -- An apk that provides additional
176 * resources to another apk.</li>
177 *
178 * <li><b>OMS</b> -- The OverlayManagerService, i.e. this class.</li>
179 *
180 * <li><b>approved</b> -- An overlay is approved if the OMS has verified
181 * that it can be used technically speaking (its target package is
182 * installed, at least one resource name in both packages match, the
183 * idmap was created, etc) and that it is secure to do so. External
184 * clients can not change this state.</li>
185 *
186 * <li><b>not approved</b> -- The opposite of approved.</li>
187 *
188 * <li><b>enabled</b> -- An overlay currently in active use and thus part
189 * of resource lookups. This requires the overlay to be approved. Only
190 * external clients can change this state.</li>
191 *
192 * <li><b>disabled</b> -- The opposite of enabled.</li>
193 *
194 * <li><b>idmap</b> -- A mapping of resource IDs between target and overlay
195 * used during resource lookup. Also the name of the binary that creates
196 * the mapping.</li>
197 * </ul>
198 */
199public final class OverlayManagerService extends SystemService {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100200 static final String TAG = "OverlayManager";
201
202 static final boolean DEBUG = false;
203
Adam Lesinskia5ca6242017-03-01 15:45:12 -0800204 /**
205 * The system property that specifies the default overlays to apply.
206 * This is a semicolon separated list of package names.
207 *
208 * Ex: com.android.vendor.overlay_one;com.android.vendor.overlay_two
209 */
210 private static final String DEFAULT_OVERLAYS_PROP = "ro.boot.vendor.overlay.theme";
211
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100212 private final Object mLock = new Object();
213
214 private final AtomicFile mSettingsFile;
215
216 private final PackageManagerHelper mPackageManager;
217
218 private final UserManagerService mUserManager;
219
220 private final OverlayManagerSettings mSettings;
221
222 private final OverlayManagerServiceImpl mImpl;
223
224 private final AtomicBoolean mPersistSettingsScheduled = new AtomicBoolean(false);
225
226 public OverlayManagerService(@NonNull final Context context,
227 @NonNull final Installer installer) {
228 super(context);
229 mSettingsFile =
Dianne Hackborne17b4452018-01-10 13:15:40 -0800230 new AtomicFile(new File(Environment.getDataSystemDirectory(), "overlays.xml"), "overlays");
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100231 mPackageManager = new PackageManagerHelper();
232 mUserManager = UserManagerService.getInstance();
233 IdmapManager im = new IdmapManager(installer);
234 mSettings = new OverlayManagerSettings();
Adam Lesinskia5ca6242017-03-01 15:45:12 -0800235 mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
Adam Lesinskic745f422017-04-05 16:31:30 -0700236 getDefaultOverlayPackages(), new OverlayChangeListener());
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100237
Mårten Kongstadcd78e0f2018-05-23 10:41:35 +0200238 final IntentFilter packageFilter = new IntentFilter();
239 packageFilter.addAction(ACTION_PACKAGE_ADDED);
240 packageFilter.addAction(ACTION_PACKAGE_CHANGED);
241 packageFilter.addAction(ACTION_PACKAGE_REMOVED);
242 packageFilter.addDataScheme("package");
243 getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL,
244 packageFilter, null, null);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100245
Mårten Kongstadcd78e0f2018-05-23 10:41:35 +0200246 final IntentFilter userFilter = new IntentFilter();
247 userFilter.addAction(ACTION_USER_ADDED);
248 userFilter.addAction(ACTION_USER_REMOVED);
249 getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL,
250 userFilter, null, null);
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700251
Mårten Kongstadcd78e0f2018-05-23 10:41:35 +0200252 restoreSettings();
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100253
Mårten Kongstadcd78e0f2018-05-23 10:41:35 +0200254 initIfNeeded();
255 onSwitchUser(UserHandle.USER_SYSTEM);
256
257 publishBinderService(Context.OVERLAY_SERVICE, mService);
258 publishLocalService(OverlayManagerService.class, this);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100259 }
260
261 @Override
262 public void onStart() {
263 // Intentionally left empty.
264 }
265
Adrian Roos9ee5dff2018-08-22 20:19:49 +0200266 public void updateSystemUiContext() {
Adrian Roos9ee5dff2018-08-22 20:19:49 +0200267 final ApplicationInfo ai;
268 try {
269 ai = mPackageManager.mPackageManager.getApplicationInfo("android",
270 GET_SHARED_LIBRARY_FILES, UserHandle.USER_SYSTEM);
271 } catch (RemoteException e) {
272 throw e.rethrowAsRuntimeException();
273 }
274 ActivityThread.currentActivityThread().handleSystemApplicationInfoChanged(ai);
275 }
276
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700277 private void initIfNeeded() {
278 final UserManager um = getContext().getSystemService(UserManager.class);
279 final List<UserInfo> users = um.getUsers(true /*excludeDying*/);
280 synchronized (mLock) {
281 final int userCount = users.size();
282 for (int i = 0; i < userCount; i++) {
283 final UserInfo userInfo = users.get(i);
284 if (!userInfo.supportsSwitchTo() && userInfo.id != UserHandle.USER_SYSTEM) {
285 // Initialize any users that can't be switched to, as there state would
286 // never be setup in onSwitchUser(). We will switch to the system user right
287 // after this, and its state will be setup there.
288 final List<String> targets = mImpl.updateOverlaysForUser(users.get(i).id);
289 updateOverlayPaths(users.get(i).id, targets);
290 }
291 }
292 }
293 }
294
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800295 @Override
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100296 public void onSwitchUser(final int newUserId) {
297 // ensure overlays in the settings are up-to-date, and propagate
298 // any asset changes to the rest of the system
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100299 synchronized (mLock) {
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700300 final List<String> targets = mImpl.updateOverlaysForUser(newUserId);
301 updateAssets(newUserId, targets);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100302 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700303 schedulePersistSettings();
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100304 }
305
Adam Lesinski7b031812018-02-22 13:32:53 -0800306 private static String[] getDefaultOverlayPackages() {
Adam Lesinskia5ca6242017-03-01 15:45:12 -0800307 final String str = SystemProperties.get(DEFAULT_OVERLAYS_PROP);
308 if (TextUtils.isEmpty(str)) {
Adam Lesinski7b031812018-02-22 13:32:53 -0800309 return EmptyArray.STRING;
Adam Lesinskia5ca6242017-03-01 15:45:12 -0800310 }
311
312 final ArraySet<String> defaultPackages = new ArraySet<>();
313 for (String packageName : str.split(";")) {
314 if (!TextUtils.isEmpty(packageName)) {
315 defaultPackages.add(packageName);
316 }
317 }
Adam Lesinski7b031812018-02-22 13:32:53 -0800318 return defaultPackages.toArray(new String[defaultPackages.size()]);
Adam Lesinskia5ca6242017-03-01 15:45:12 -0800319 }
320
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100321 private final class PackageReceiver extends BroadcastReceiver {
322 @Override
323 public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
324 final Uri data = intent.getData();
325 if (data == null) {
326 Slog.e(TAG, "Cannot handle package broadcast with null data");
327 return;
328 }
329 final String packageName = data.getSchemeSpecificPart();
330
331 final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
332
333 final int[] userIds;
334 final int extraUid = intent.getIntExtra(Intent.EXTRA_UID, UserHandle.USER_NULL);
335 if (extraUid == UserHandle.USER_NULL) {
336 userIds = mUserManager.getUserIds();
337 } else {
338 userIds = new int[] { UserHandle.getUserId(extraUid) };
339 }
340
341 switch (intent.getAction()) {
342 case ACTION_PACKAGE_ADDED:
343 if (replacing) {
344 onPackageUpgraded(packageName, userIds);
345 } else {
346 onPackageAdded(packageName, userIds);
347 }
348 break;
349 case ACTION_PACKAGE_CHANGED:
350 onPackageChanged(packageName, userIds);
351 break;
352 case ACTION_PACKAGE_REMOVED:
353 if (replacing) {
354 onPackageUpgrading(packageName, userIds);
355 } else {
356 onPackageRemoved(packageName, userIds);
357 }
358 break;
359 default:
360 // do nothing
361 break;
362 }
363 }
364
365 private void onPackageAdded(@NonNull final String packageName,
366 @NonNull final int[] userIds) {
367 for (final int userId : userIds) {
368 synchronized (mLock) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700369 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
370 false);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100371 if (pi != null) {
372 mPackageManager.cachePackageInfo(packageName, userId, pi);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800373 if (pi.isOverlayPackage()) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100374 mImpl.onOverlayPackageAdded(packageName, userId);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800375 } else {
376 mImpl.onTargetPackageAdded(packageName, userId);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100377 }
378 }
379 }
380 }
381 }
382
383 private void onPackageChanged(@NonNull final String packageName,
384 @NonNull final int[] userIds) {
385 for (int userId : userIds) {
386 synchronized (mLock) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700387 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
388 false);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100389 if (pi != null) {
390 mPackageManager.cachePackageInfo(packageName, userId, pi);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800391 if (pi.isOverlayPackage()) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100392 mImpl.onOverlayPackageChanged(packageName, userId);
Ryan Mitchelld41d0db2018-05-09 09:01:12 -0700393 } else {
394 mImpl.onTargetPackageChanged(packageName, userId);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100395 }
396 }
397 }
398 }
399 }
400
401 private void onPackageUpgrading(@NonNull final String packageName,
402 @NonNull final int[] userIds) {
403 for (int userId : userIds) {
404 synchronized (mLock) {
405 mPackageManager.forgetPackageInfo(packageName, userId);
406 final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800407 if (oi != null) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100408 mImpl.onOverlayPackageUpgrading(packageName, userId);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800409 } else {
410 mImpl.onTargetPackageUpgrading(packageName, userId);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100411 }
412 }
413 }
414 }
415
416 private void onPackageUpgraded(@NonNull final String packageName,
417 @NonNull final int[] userIds) {
418 for (int userId : userIds) {
419 synchronized (mLock) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700420 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
421 false);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100422 if (pi != null) {
423 mPackageManager.cachePackageInfo(packageName, userId, pi);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800424 if (pi.isOverlayPackage()) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100425 mImpl.onOverlayPackageUpgraded(packageName, userId);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800426 } else {
427 mImpl.onTargetPackageUpgraded(packageName, userId);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100428 }
429 }
430 }
431 }
432 }
433
434 private void onPackageRemoved(@NonNull final String packageName,
435 @NonNull final int[] userIds) {
436 for (int userId : userIds) {
437 synchronized (mLock) {
438 mPackageManager.forgetPackageInfo(packageName, userId);
439 final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800440 if (oi != null) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100441 mImpl.onOverlayPackageRemoved(packageName, userId);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800442 } else {
443 mImpl.onTargetPackageRemoved(packageName, userId);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100444 }
445 }
446 }
447 }
448 }
449
450 private final class UserReceiver extends BroadcastReceiver {
451 @Override
452 public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700453 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100454 switch (intent.getAction()) {
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700455 case ACTION_USER_ADDED:
456 if (userId != UserHandle.USER_NULL) {
457 final ArrayList<String> targets;
458 synchronized (mLock) {
459 targets = mImpl.updateOverlaysForUser(userId);
460 }
461 updateOverlayPaths(userId, targets);
462 }
463 break;
464
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100465 case ACTION_USER_REMOVED:
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100466 if (userId != UserHandle.USER_NULL) {
467 synchronized (mLock) {
468 mImpl.onUserRemoved(userId);
469 mPackageManager.forgetAllPackageInfos(userId);
470 }
471 }
472 break;
473 default:
474 // do nothing
475 break;
476 }
477 }
478 }
479
480 private final IBinder mService = new IOverlayManager.Stub() {
481 @Override
Adam Lesinskic745f422017-04-05 16:31:30 -0700482 public Map<String, List<OverlayInfo>> getAllOverlays(int userId) throws RemoteException {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100483 userId = handleIncomingUser(userId, "getAllOverlays");
484
485 synchronized (mLock) {
486 return mImpl.getOverlaysForUser(userId);
487 }
488 }
489
490 @Override
491 public List<OverlayInfo> getOverlayInfosForTarget(@Nullable final String targetPackageName,
492 int userId) throws RemoteException {
493 userId = handleIncomingUser(userId, "getOverlayInfosForTarget");
494 if (targetPackageName == null) {
495 return Collections.emptyList();
496 }
497
498 synchronized (mLock) {
499 return mImpl.getOverlayInfosForTarget(targetPackageName, userId);
500 }
501 }
502
503 @Override
504 public OverlayInfo getOverlayInfo(@Nullable final String packageName,
505 int userId) throws RemoteException {
506 userId = handleIncomingUser(userId, "getOverlayInfo");
507 if (packageName == null) {
508 return null;
509 }
510
511 synchronized (mLock) {
512 return mImpl.getOverlayInfo(packageName, userId);
513 }
514 }
515
516 @Override
517 public boolean setEnabled(@Nullable final String packageName, final boolean enable,
518 int userId) throws RemoteException {
519 enforceChangeOverlayPackagesPermission("setEnabled");
520 userId = handleIncomingUser(userId, "setEnabled");
521 if (packageName == null) {
522 return false;
523 }
524
525 final long ident = Binder.clearCallingIdentity();
526 try {
527 synchronized (mLock) {
528 return mImpl.setEnabled(packageName, enable, userId);
529 }
530 } finally {
531 Binder.restoreCallingIdentity(ident);
532 }
533 }
534
535 @Override
Jason Monk929ed8d2017-03-07 16:01:20 -0500536 public boolean setEnabledExclusive(@Nullable final String packageName, final boolean enable,
537 int userId) throws RemoteException {
Mårten Kongstadd7191552018-06-08 08:51:13 +0200538 enforceChangeOverlayPackagesPermission("setEnabledExclusive");
539 userId = handleIncomingUser(userId, "setEnabledExclusive");
Adam Lesinskic745f422017-04-05 16:31:30 -0700540 if (packageName == null || !enable) {
Jason Monk929ed8d2017-03-07 16:01:20 -0500541 return false;
542 }
543
544 final long ident = Binder.clearCallingIdentity();
545 try {
546 synchronized (mLock) {
Adrian Roosc84df772018-01-19 21:20:22 +0100547 return mImpl.setEnabledExclusive(packageName, false /* withinCategory */,
548 userId);
549 }
550 } finally {
551 Binder.restoreCallingIdentity(ident);
552 }
553 }
554
555 @Override
556 public boolean setEnabledExclusiveInCategory(@Nullable String packageName, int userId)
557 throws RemoteException {
Mårten Kongstadd7191552018-06-08 08:51:13 +0200558 enforceChangeOverlayPackagesPermission("setEnabledExclusiveInCategory");
559 userId = handleIncomingUser(userId, "setEnabledExclusiveInCategory");
Adrian Roosc84df772018-01-19 21:20:22 +0100560 if (packageName == null) {
561 return false;
562 }
563
564 final long ident = Binder.clearCallingIdentity();
565 try {
566 synchronized (mLock) {
567 return mImpl.setEnabledExclusive(packageName, true /* withinCategory */,
568 userId);
Jason Monk929ed8d2017-03-07 16:01:20 -0500569 }
570 } finally {
571 Binder.restoreCallingIdentity(ident);
572 }
573 }
574
575 @Override
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100576 public boolean setPriority(@Nullable final String packageName,
577 @Nullable final String parentPackageName, int userId) throws RemoteException {
578 enforceChangeOverlayPackagesPermission("setPriority");
579 userId = handleIncomingUser(userId, "setPriority");
580 if (packageName == null || parentPackageName == null) {
581 return false;
582 }
583
584 final long ident = Binder.clearCallingIdentity();
585 try {
586 synchronized (mLock) {
587 return mImpl.setPriority(packageName, parentPackageName, userId);
588 }
589 } finally {
590 Binder.restoreCallingIdentity(ident);
591 }
592 }
593
594 @Override
595 public boolean setHighestPriority(@Nullable final String packageName, int userId)
596 throws RemoteException {
597 enforceChangeOverlayPackagesPermission("setHighestPriority");
598 userId = handleIncomingUser(userId, "setHighestPriority");
599 if (packageName == null) {
600 return false;
601 }
602
603 final long ident = Binder.clearCallingIdentity();
604 try {
605 synchronized (mLock) {
606 return mImpl.setHighestPriority(packageName, userId);
607 }
608 } finally {
609 Binder.restoreCallingIdentity(ident);
610 }
611 }
612
613 @Override
614 public boolean setLowestPriority(@Nullable final String packageName, int userId)
615 throws RemoteException {
616 enforceChangeOverlayPackagesPermission("setLowestPriority");
617 userId = handleIncomingUser(userId, "setLowestPriority");
618 if (packageName == null) {
619 return false;
620 }
621
622 final long ident = Binder.clearCallingIdentity();
623 try {
624 synchronized (mLock) {
625 return mImpl.setLowestPriority(packageName, userId);
626 }
627 } finally {
628 Binder.restoreCallingIdentity(ident);
629 }
630 }
631
632 @Override
633 public void onShellCommand(@NonNull final FileDescriptor in,
634 @NonNull final FileDescriptor out, @NonNull final FileDescriptor err,
635 @NonNull final String[] args, @NonNull final ShellCallback callback,
636 @NonNull final ResultReceiver resultReceiver) {
637 (new OverlayManagerShellCommand(this)).exec(
638 this, in, out, err, args, callback, resultReceiver);
639 }
640
641 @Override
642 protected void dump(@NonNull final FileDescriptor fd, @NonNull final PrintWriter pw,
643 @NonNull final String[] argv) {
644 enforceDumpPermission("dump");
645
646 final boolean verbose = argv.length > 0 && "--verbose".equals(argv[0]);
647
648 synchronized (mLock) {
649 mImpl.onDump(pw);
650 mPackageManager.dump(pw, verbose);
651 }
652 }
653
654 /**
655 * Ensure that the caller has permission to interact with the given userId.
656 * If the calling user is not the same as the provided user, the caller needs
657 * to hold the INTERACT_ACROSS_USERS_FULL permission (or be system uid or
658 * root).
659 *
660 * @param userId the user to interact with
661 * @param message message for any SecurityException
662 */
663 private int handleIncomingUser(final int userId, @NonNull final String message) {
664 return ActivityManager.handleIncomingUser(Binder.getCallingPid(),
665 Binder.getCallingUid(), userId, false, true, message, null);
666 }
667
668 /**
669 * Enforce that the caller holds the CHANGE_OVERLAY_PACKAGES permission (or is
670 * system or root).
671 *
672 * @param message used as message if SecurityException is thrown
673 * @throws SecurityException if the permission check fails
674 */
675 private void enforceChangeOverlayPackagesPermission(@NonNull final String message) {
Mårten Kongstadf28bec42017-11-16 13:07:30 +0100676 getContext().enforceCallingPermission(
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100677 android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, message);
678 }
679
680 /**
681 * Enforce that the caller holds the DUMP permission (or is system or root).
682 *
683 * @param message used as message if SecurityException is thrown
684 * @throws SecurityException if the permission check fails
685 */
686 private void enforceDumpPermission(@NonNull final String message) {
Mårten Kongstadf28bec42017-11-16 13:07:30 +0100687 getContext().enforceCallingPermission(android.Manifest.permission.DUMP, message);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100688 }
689 };
690
Adam Lesinskic745f422017-04-05 16:31:30 -0700691 private final class OverlayChangeListener
692 implements OverlayManagerServiceImpl.OverlayChangeListener {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100693 @Override
Mårten Kongstad497945c2018-04-27 09:56:13 +0200694 public void onOverlaysChanged(@NonNull final String targetPackageName, final int userId) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100695 schedulePersistSettings();
Adam Lesinskic745f422017-04-05 16:31:30 -0700696 FgThread.getHandler().post(() -> {
Mårten Kongstad497945c2018-04-27 09:56:13 +0200697 updateAssets(userId, targetPackageName);
698
699 final Intent intent = new Intent(Intent.ACTION_OVERLAY_CHANGED,
700 Uri.fromParts("package", targetPackageName, null));
701 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
702
703 if (DEBUG) {
704 Slog.d(TAG, "send broadcast " + intent);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100705 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700706
Mårten Kongstad497945c2018-04-27 09:56:13 +0200707 try {
708 ActivityManager.getService().broadcastIntent(null, intent, null, null, 0,
709 null, null, null, android.app.AppOpsManager.OP_NONE, null, false, false,
710 userId);
711 } catch (RemoteException e) {
712 // Intentionally left empty.
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100713 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700714 });
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100715 }
716 }
717
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700718 /**
719 * Updates the target packages' set of enabled overlays in PackageManager.
720 */
721 private void updateOverlayPaths(int userId, List<String> targetPackageNames) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700722 if (DEBUG) {
723 Slog.d(TAG, "Updating overlay assets");
724 }
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200725 final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
726 final boolean updateFrameworkRes = targetPackageNames.contains("android");
727 if (updateFrameworkRes) {
728 targetPackageNames = pm.getTargetPackageNames(userId);
729 }
730
731 final Map<String, List<String>> pendingChanges = new ArrayMap<>(targetPackageNames.size());
732 synchronized (mLock) {
Todd Kennedy560830c2017-06-16 13:55:13 -0700733 final List<String> frameworkOverlays =
734 mImpl.getEnabledOverlayPackageNames("android", userId);
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200735 final int N = targetPackageNames.size();
736 for (int i = 0; i < N; i++) {
737 final String targetPackageName = targetPackageNames.get(i);
Todd Kennedy560830c2017-06-16 13:55:13 -0700738 List<String> list = new ArrayList<>();
739 if (!"android".equals(targetPackageName)) {
740 list.addAll(frameworkOverlays);
741 }
742 list.addAll(mImpl.getEnabledOverlayPackageNames(targetPackageName, userId));
743 pendingChanges.put(targetPackageName, list);
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200744 }
745 }
746
747 final int N = targetPackageNames.size();
748 for (int i = 0; i < N; i++) {
749 final String targetPackageName = targetPackageNames.get(i);
Adam Lesinskic745f422017-04-05 16:31:30 -0700750 if (DEBUG) {
751 Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=["
752 + TextUtils.join(",", pendingChanges.get(targetPackageName))
753 + "] userId=" + userId);
754 }
755
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200756 if (!pm.setEnabledOverlayPackages(
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700757 userId, targetPackageName, pendingChanges.get(targetPackageName))) {
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200758 Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700759 targetPackageName, userId));
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200760 }
761 }
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700762 }
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200763
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700764 private void updateAssets(final int userId, final String targetPackageName) {
765 updateAssets(userId, Collections.singletonList(targetPackageName));
766 }
767
768 private void updateAssets(final int userId, List<String> targetPackageNames) {
769 updateOverlayPaths(userId, targetPackageNames);
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200770 final IActivityManager am = ActivityManager.getService();
771 try {
772 am.scheduleApplicationInfoChanged(targetPackageNames, userId);
773 } catch (RemoteException e) {
774 // Intentionally left empty.
775 }
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100776 }
777
778 private void schedulePersistSettings() {
779 if (mPersistSettingsScheduled.getAndSet(true)) {
780 return;
781 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700782 IoThread.getHandler().post(() -> {
783 mPersistSettingsScheduled.set(false);
784 if (DEBUG) {
785 Slog.d(TAG, "Writing overlay settings");
786 }
787 synchronized (mLock) {
788 FileOutputStream stream = null;
789 try {
790 stream = mSettingsFile.startWrite();
791 mSettings.persist(stream);
792 mSettingsFile.finishWrite(stream);
793 } catch (IOException | XmlPullParserException e) {
794 mSettingsFile.failWrite(stream);
795 Slog.e(TAG, "failed to persist overlay state", e);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100796 }
797 }
798 });
799 }
800
801 private void restoreSettings() {
802 synchronized (mLock) {
803 if (!mSettingsFile.getBaseFile().exists()) {
804 return;
805 }
806 try (final FileInputStream stream = mSettingsFile.openRead()) {
807 mSettings.restore(stream);
808
809 // We might have data for dying users if the device was
810 // restarted before we received USER_REMOVED. Remove data for
811 // users that will not exist after the system is ready.
812
Adam Lesinskid11c5512017-04-11 12:01:10 -0700813 final List<UserInfo> liveUsers = mUserManager.getUsers(true /*excludeDying*/);
814 final int[] liveUserIds = new int[liveUsers.size()];
815 for (int i = 0; i < liveUsers.size(); i++) {
816 liveUserIds[i] = liveUsers.get(i).getUserHandle().getIdentifier();
817 }
818 Arrays.sort(liveUserIds);
819
820 for (int userId : mSettings.getUsers()) {
821 if (Arrays.binarySearch(liveUserIds, userId) < 0) {
822 mSettings.removeUser(userId);
823 }
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100824 }
825 } catch (IOException | XmlPullParserException e) {
826 Slog.e(TAG, "failed to restore overlay state", e);
827 }
828 }
829 }
830
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100831 private static final class PackageManagerHelper implements
832 OverlayManagerServiceImpl.PackageManagerHelper {
833
834 private final IPackageManager mPackageManager;
835 private final PackageManagerInternal mPackageManagerInternal;
836
837 // Use a cache for performance and for consistency within OMS: because
838 // additional PACKAGE_* intents may be delivered while we process an
839 // intent, querying the PackageManagerService for the actual current
840 // state may lead to contradictions within OMS. Better then to lag
841 // behind until all pending intents have been processed.
842 private final SparseArray<HashMap<String, PackageInfo>> mCache = new SparseArray<>();
843
844 PackageManagerHelper() {
845 mPackageManager = getPackageManager();
846 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
847 }
848
849 public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId,
850 final boolean useCache) {
851 if (useCache) {
852 final PackageInfo cachedPi = getCachedPackageInfo(packageName, userId);
853 if (cachedPi != null) {
854 return cachedPi;
855 }
856 }
857 try {
858 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0, userId);
859 if (useCache && pi != null) {
860 cachePackageInfo(packageName, userId, pi);
861 }
862 return pi;
863 } catch (RemoteException e) {
864 // Intentionally left empty.
865 }
866 return null;
867 }
868
869 @Override
870 public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId) {
871 return getPackageInfo(packageName, userId, true);
872 }
873
874 @Override
875 public boolean signaturesMatching(@NonNull final String packageName1,
876 @NonNull final String packageName2, final int userId) {
877 // The package manager does not support different versions of packages
878 // to be installed for different users: ignore userId for now.
879 try {
Adam Lesinskic745f422017-04-05 16:31:30 -0700880 return mPackageManager.checkSignatures(
881 packageName1, packageName2) == SIGNATURE_MATCH;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100882 } catch (RemoteException e) {
883 // Intentionally left blank
884 }
885 return false;
886 }
887
888 @Override
889 public List<PackageInfo> getOverlayPackages(final int userId) {
890 return mPackageManagerInternal.getOverlayPackages(userId);
891 }
892
893 public PackageInfo getCachedPackageInfo(@NonNull final String packageName,
894 final int userId) {
895 final HashMap<String, PackageInfo> map = mCache.get(userId);
896 return map == null ? null : map.get(packageName);
897 }
898
899 public void cachePackageInfo(@NonNull final String packageName, final int userId,
900 @NonNull final PackageInfo pi) {
901 HashMap<String, PackageInfo> map = mCache.get(userId);
902 if (map == null) {
903 map = new HashMap<>();
904 mCache.put(userId, map);
905 }
906 map.put(packageName, pi);
907 }
908
909 public void forgetPackageInfo(@NonNull final String packageName, final int userId) {
910 final HashMap<String, PackageInfo> map = mCache.get(userId);
911 if (map == null) {
912 return;
913 }
914 map.remove(packageName);
915 if (map.isEmpty()) {
916 mCache.delete(userId);
917 }
918 }
919
920 public void forgetAllPackageInfos(final int userId) {
921 mCache.delete(userId);
922 }
923
924 private static final String TAB1 = " ";
925 private static final String TAB2 = TAB1 + TAB1;
926
927 public void dump(@NonNull final PrintWriter pw, final boolean verbose) {
928 pw.println("PackageInfo cache");
929
930 if (!verbose) {
931 int count = 0;
932 final int N = mCache.size();
933 for (int i = 0; i < N; i++) {
934 final int userId = mCache.keyAt(i);
935 count += mCache.get(userId).size();
936 }
937 pw.println(TAB1 + count + " package(s)");
938 return;
939 }
940
941 if (mCache.size() == 0) {
942 pw.println(TAB1 + "<empty>");
943 return;
944 }
945
946 final int N = mCache.size();
947 for (int i = 0; i < N; i++) {
948 final int userId = mCache.keyAt(i);
949 pw.println(TAB1 + "User " + userId);
950 final HashMap<String, PackageInfo> map = mCache.get(userId);
951 for (Map.Entry<String, PackageInfo> entry : map.entrySet()) {
952 pw.println(TAB2 + entry.getKey() + ": " + entry.getValue());
953 }
954 }
955 }
956 }
957}