blob: fd51be5773080070f6e86ac356b3bd5f44b9e69d [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
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -080058import com.android.internal.util.ConcurrentUtils;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010059import com.android.server.FgThread;
60import com.android.server.IoThread;
61import com.android.server.LocalServices;
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -080062import com.android.server.SystemServerInitThreadPool;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010063import com.android.server.SystemService;
64import com.android.server.pm.Installer;
65import com.android.server.pm.UserManagerService;
66
Adam Lesinski7b031812018-02-22 13:32:53 -080067import libcore.util.EmptyArray;
68
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010069import org.xmlpull.v1.XmlPullParserException;
70
71import java.io.File;
72import java.io.FileDescriptor;
73import java.io.FileInputStream;
74import java.io.FileOutputStream;
75import java.io.IOException;
76import java.io.PrintWriter;
77import java.util.ArrayList;
Adam Lesinskid11c5512017-04-11 12:01:10 -070078import java.util.Arrays;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010079import java.util.Collections;
80import java.util.HashMap;
81import java.util.List;
82import java.util.Map;
Adam Lesinskia5ca6242017-03-01 15:45:12 -080083import java.util.Set;
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -080084import java.util.concurrent.Future;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010085import java.util.concurrent.atomic.AtomicBoolean;
86
87/**
88 * Service to manage asset overlays.
89 *
90 * <p>Asset overlays are additional resources that come from apks loaded
91 * alongside the system and app apks. This service, the OverlayManagerService
92 * (OMS), tracks which installed overlays to use and provides methods to change
93 * this. Changes propagate to running applications as part of the Activity
94 * lifecycle. This allows Activities to reread their resources at a well
95 * defined point.</p>
96 *
97 * <p>By itself, the OMS will not change what overlays should be active.
98 * Instead, it is only responsible for making sure that overlays *can* be used
99 * from a technical and security point of view and to activate overlays in
100 * response to external requests. The responsibility to toggle overlays on and
101 * off lies within components that implement different use-cases such as themes
102 * or dynamic customization.</p>
103 *
104 * <p>The OMS receives input from three sources:</p>
105 *
106 * <ul>
107 * <li>Callbacks from the SystemService class, specifically when the
108 * Android framework is booting and when the end user switches Android
109 * users.</li>
110 *
111 * <li>Intents from the PackageManagerService (PMS). Overlays are regular
112 * apks, and whenever a package is installed (or removed, or has a
113 * component enabled or disabled), the PMS broadcasts this as an intent.
114 * When the OMS receives one of these intents, it updates its internal
115 * representation of the available overlays and, if there was a visible
116 * change, triggers an asset refresh in the affected apps.</li>
117 *
118 * <li>External requests via the {@link IOverlayManager AIDL interface}.
119 * The interface allows clients to read information about the currently
120 * available overlays, change whether an overlay should be used or not, and
121 * change the relative order in which overlay packages are loaded.
122 * Read-access is granted if the request targets the same Android user as
123 * the caller runs as, or if the caller holds the
124 * INTERACT_ACROSS_USERS_FULL permission. Write-access is granted if the
125 * caller is granted read-access and additionaly holds the
126 * CHANGE_OVERLAY_PACKAGES permission.</li>
127 * </ul>
128 *
129 * <p>The AIDL interface works with String package names, int user IDs, and
130 * {@link OverlayInfo} objects. OverlayInfo instances are used to track a
131 * specific pair of target and overlay packages and include information such as
132 * the current state of the overlay. OverlayInfo objects are immutable.</p>
133 *
134 * <p>Internally, OverlayInfo objects are maintained by the
135 * OverlayManagerSettings class. The OMS and its helper classes are notified of
136 * changes to the settings by the OverlayManagerSettings.ChangeListener
137 * callback interface. The file /data/system/overlays.xml is used to persist
138 * the settings.</p>
139 *
140 * <p>Creation and deletion of idmap files are handled by the IdmapManager
141 * class.</p>
142 *
143 * <p>The following is an overview of OMS and its related classes. Note how box
144 * (2) does the heavy lifting, box (1) interacts with the Android framework,
145 * and box (3) replaces box (1) during unit testing.</p>
146 *
147 * <pre>
148 * Android framework
149 * | ^
150 * . . . | . . . . | . . . .
151 * . | | .
152 * . AIDL, broadcasts .
153 * . intents | .
154 * . | | . . . . . . . . . . . .
155 * . v | . .
156 * . OverlayManagerService . OverlayManagerTests .
157 * . \ . / .
158 * . (1) \ . / (3) .
159 * . . . . . . . . . . \ . . . / . . . . . . . . .
160 * . \ / .
161 * . (2) \ / .
162 * . OverlayManagerServiceImpl .
163 * . | | .
164 * . | | .
165 * . OverlayManagerSettings IdmapManager .
166 * . .
167 * . . . . . . . . . . . . . . . . . . . . . .
168 * </pre>
169 *
170 * <p>Finally, here is a list of keywords used in the OMS context.</p>
171 *
172 * <ul>
173 * <li><b>target [package]</b> -- A regular apk that may have its resource
174 * pool extended by zero or more overlay packages.</li>
175 *
176 * <li><b>overlay [package]</b> -- An apk that provides additional
177 * resources to another apk.</li>
178 *
179 * <li><b>OMS</b> -- The OverlayManagerService, i.e. this class.</li>
180 *
181 * <li><b>approved</b> -- An overlay is approved if the OMS has verified
182 * that it can be used technically speaking (its target package is
183 * installed, at least one resource name in both packages match, the
184 * idmap was created, etc) and that it is secure to do so. External
185 * clients can not change this state.</li>
186 *
187 * <li><b>not approved</b> -- The opposite of approved.</li>
188 *
189 * <li><b>enabled</b> -- An overlay currently in active use and thus part
190 * of resource lookups. This requires the overlay to be approved. Only
191 * external clients can change this state.</li>
192 *
193 * <li><b>disabled</b> -- The opposite of enabled.</li>
194 *
195 * <li><b>idmap</b> -- A mapping of resource IDs between target and overlay
196 * used during resource lookup. Also the name of the binary that creates
197 * the mapping.</li>
198 * </ul>
199 */
200public final class OverlayManagerService extends SystemService {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100201 static final String TAG = "OverlayManager";
202
203 static final boolean DEBUG = false;
204
Adam Lesinskia5ca6242017-03-01 15:45:12 -0800205 /**
206 * The system property that specifies the default overlays to apply.
207 * This is a semicolon separated list of package names.
208 *
209 * Ex: com.android.vendor.overlay_one;com.android.vendor.overlay_two
210 */
211 private static final String DEFAULT_OVERLAYS_PROP = "ro.boot.vendor.overlay.theme";
212
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100213 private final Object mLock = new Object();
214
215 private final AtomicFile mSettingsFile;
216
217 private final PackageManagerHelper mPackageManager;
218
219 private final UserManagerService mUserManager;
220
221 private final OverlayManagerSettings mSettings;
222
223 private final OverlayManagerServiceImpl mImpl;
224
225 private final AtomicBoolean mPersistSettingsScheduled = new AtomicBoolean(false);
226
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800227 private Future<?> mInitCompleteSignal;
228
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100229 public OverlayManagerService(@NonNull final Context context,
230 @NonNull final Installer installer) {
231 super(context);
232 mSettingsFile =
Dianne Hackborne17b4452018-01-10 13:15:40 -0800233 new AtomicFile(new File(Environment.getDataSystemDirectory(), "overlays.xml"), "overlays");
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100234 mPackageManager = new PackageManagerHelper();
235 mUserManager = UserManagerService.getInstance();
236 IdmapManager im = new IdmapManager(installer);
237 mSettings = new OverlayManagerSettings();
Adam Lesinskia5ca6242017-03-01 15:45:12 -0800238 mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
Adam Lesinskic745f422017-04-05 16:31:30 -0700239 getDefaultOverlayPackages(), new OverlayChangeListener());
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800240 mInitCompleteSignal = SystemServerInitThreadPool.get().submit(() -> {
241 final IntentFilter packageFilter = new IntentFilter();
242 packageFilter.addAction(ACTION_PACKAGE_ADDED);
243 packageFilter.addAction(ACTION_PACKAGE_CHANGED);
244 packageFilter.addAction(ACTION_PACKAGE_REMOVED);
245 packageFilter.addDataScheme("package");
246 getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL,
247 packageFilter, null, null);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100248
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800249 final IntentFilter userFilter = new IntentFilter();
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700250 userFilter.addAction(ACTION_USER_ADDED);
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800251 userFilter.addAction(ACTION_USER_REMOVED);
252 getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL,
253 userFilter, null, null);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100254
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800255 restoreSettings();
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700256
257 initIfNeeded();
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800258 onSwitchUser(UserHandle.USER_SYSTEM);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100259
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800260 publishBinderService(Context.OVERLAY_SERVICE, mService);
261 publishLocalService(OverlayManagerService.class, this);
262 }, "Init OverlayManagerService");
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100263 }
264
265 @Override
266 public void onStart() {
267 // Intentionally left empty.
268 }
269
270 @Override
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800271 public void onBootPhase(int phase) {
272 if (phase == PHASE_SYSTEM_SERVICES_READY) {
273 ConcurrentUtils.waitForFutureNoInterrupt(mInitCompleteSignal,
274 "Wait for OverlayManagerService init");
275 mInitCompleteSignal = null;
276 }
277 }
278
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700279 private void initIfNeeded() {
280 final UserManager um = getContext().getSystemService(UserManager.class);
281 final List<UserInfo> users = um.getUsers(true /*excludeDying*/);
282 synchronized (mLock) {
283 final int userCount = users.size();
284 for (int i = 0; i < userCount; i++) {
285 final UserInfo userInfo = users.get(i);
286 if (!userInfo.supportsSwitchTo() && userInfo.id != UserHandle.USER_SYSTEM) {
287 // Initialize any users that can't be switched to, as there state would
288 // never be setup in onSwitchUser(). We will switch to the system user right
289 // after this, and its state will be setup there.
290 final List<String> targets = mImpl.updateOverlaysForUser(users.get(i).id);
291 updateOverlayPaths(users.get(i).id, targets);
292 }
293 }
294 }
295 }
296
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800297 @Override
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100298 public void onSwitchUser(final int newUserId) {
299 // ensure overlays in the settings are up-to-date, and propagate
300 // any asset changes to the rest of the system
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100301 synchronized (mLock) {
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700302 final List<String> targets = mImpl.updateOverlaysForUser(newUserId);
303 updateAssets(newUserId, targets);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100304 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700305 schedulePersistSettings();
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100306 }
307
Adam Lesinski7b031812018-02-22 13:32:53 -0800308 private static String[] getDefaultOverlayPackages() {
Adam Lesinskia5ca6242017-03-01 15:45:12 -0800309 final String str = SystemProperties.get(DEFAULT_OVERLAYS_PROP);
310 if (TextUtils.isEmpty(str)) {
Adam Lesinski7b031812018-02-22 13:32:53 -0800311 return EmptyArray.STRING;
Adam Lesinskia5ca6242017-03-01 15:45:12 -0800312 }
313
314 final ArraySet<String> defaultPackages = new ArraySet<>();
315 for (String packageName : str.split(";")) {
316 if (!TextUtils.isEmpty(packageName)) {
317 defaultPackages.add(packageName);
318 }
319 }
Adam Lesinski7b031812018-02-22 13:32:53 -0800320 return defaultPackages.toArray(new String[defaultPackages.size()]);
Adam Lesinskia5ca6242017-03-01 15:45:12 -0800321 }
322
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100323 private final class PackageReceiver extends BroadcastReceiver {
324 @Override
325 public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
326 final Uri data = intent.getData();
327 if (data == null) {
328 Slog.e(TAG, "Cannot handle package broadcast with null data");
329 return;
330 }
331 final String packageName = data.getSchemeSpecificPart();
332
333 final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
334
335 final int[] userIds;
336 final int extraUid = intent.getIntExtra(Intent.EXTRA_UID, UserHandle.USER_NULL);
337 if (extraUid == UserHandle.USER_NULL) {
338 userIds = mUserManager.getUserIds();
339 } else {
340 userIds = new int[] { UserHandle.getUserId(extraUid) };
341 }
342
343 switch (intent.getAction()) {
344 case ACTION_PACKAGE_ADDED:
345 if (replacing) {
346 onPackageUpgraded(packageName, userIds);
347 } else {
348 onPackageAdded(packageName, userIds);
349 }
350 break;
351 case ACTION_PACKAGE_CHANGED:
352 onPackageChanged(packageName, userIds);
353 break;
354 case ACTION_PACKAGE_REMOVED:
355 if (replacing) {
356 onPackageUpgrading(packageName, userIds);
357 } else {
358 onPackageRemoved(packageName, userIds);
359 }
360 break;
361 default:
362 // do nothing
363 break;
364 }
365 }
366
367 private void onPackageAdded(@NonNull final String packageName,
368 @NonNull final int[] userIds) {
369 for (final int userId : userIds) {
370 synchronized (mLock) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700371 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
372 false);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100373 if (pi != null) {
374 mPackageManager.cachePackageInfo(packageName, userId, pi);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800375 if (pi.isOverlayPackage()) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100376 mImpl.onOverlayPackageAdded(packageName, userId);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800377 } else {
378 mImpl.onTargetPackageAdded(packageName, userId);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100379 }
380 }
381 }
382 }
383 }
384
385 private void onPackageChanged(@NonNull final String packageName,
386 @NonNull final int[] userIds) {
387 for (int userId : userIds) {
388 synchronized (mLock) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700389 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
390 false);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100391 if (pi != null) {
392 mPackageManager.cachePackageInfo(packageName, userId, pi);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800393 if (pi.isOverlayPackage()) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100394 mImpl.onOverlayPackageChanged(packageName, userId);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800395 } else {
396 mImpl.onTargetPackageChanged(packageName, userId);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100397 }
398 }
399 }
400 }
401 }
402
403 private void onPackageUpgrading(@NonNull final String packageName,
404 @NonNull final int[] userIds) {
405 for (int userId : userIds) {
406 synchronized (mLock) {
407 mPackageManager.forgetPackageInfo(packageName, userId);
408 final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800409 if (oi != null) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100410 mImpl.onOverlayPackageUpgrading(packageName, userId);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800411 } else {
412 mImpl.onTargetPackageUpgrading(packageName, userId);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100413 }
414 }
415 }
416 }
417
418 private void onPackageUpgraded(@NonNull final String packageName,
419 @NonNull final int[] userIds) {
420 for (int userId : userIds) {
421 synchronized (mLock) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700422 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
423 false);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100424 if (pi != null) {
425 mPackageManager.cachePackageInfo(packageName, userId, pi);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800426 if (pi.isOverlayPackage()) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100427 mImpl.onOverlayPackageUpgraded(packageName, userId);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800428 } else {
429 mImpl.onTargetPackageUpgraded(packageName, userId);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100430 }
431 }
432 }
433 }
434 }
435
436 private void onPackageRemoved(@NonNull final String packageName,
437 @NonNull final int[] userIds) {
438 for (int userId : userIds) {
439 synchronized (mLock) {
440 mPackageManager.forgetPackageInfo(packageName, userId);
441 final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800442 if (oi != null) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100443 mImpl.onOverlayPackageRemoved(packageName, userId);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800444 } else {
445 mImpl.onTargetPackageRemoved(packageName, userId);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100446 }
447 }
448 }
449 }
450 }
451
452 private final class UserReceiver extends BroadcastReceiver {
453 @Override
454 public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700455 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100456 switch (intent.getAction()) {
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700457 case ACTION_USER_ADDED:
458 if (userId != UserHandle.USER_NULL) {
459 final ArrayList<String> targets;
460 synchronized (mLock) {
461 targets = mImpl.updateOverlaysForUser(userId);
462 }
463 updateOverlayPaths(userId, targets);
464 }
465 break;
466
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100467 case ACTION_USER_REMOVED:
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100468 if (userId != UserHandle.USER_NULL) {
469 synchronized (mLock) {
470 mImpl.onUserRemoved(userId);
471 mPackageManager.forgetAllPackageInfos(userId);
472 }
473 }
474 break;
475 default:
476 // do nothing
477 break;
478 }
479 }
480 }
481
482 private final IBinder mService = new IOverlayManager.Stub() {
483 @Override
Adam Lesinskic745f422017-04-05 16:31:30 -0700484 public Map<String, List<OverlayInfo>> getAllOverlays(int userId) throws RemoteException {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100485 userId = handleIncomingUser(userId, "getAllOverlays");
486
487 synchronized (mLock) {
488 return mImpl.getOverlaysForUser(userId);
489 }
490 }
491
492 @Override
493 public List<OverlayInfo> getOverlayInfosForTarget(@Nullable final String targetPackageName,
494 int userId) throws RemoteException {
495 userId = handleIncomingUser(userId, "getOverlayInfosForTarget");
496 if (targetPackageName == null) {
497 return Collections.emptyList();
498 }
499
500 synchronized (mLock) {
501 return mImpl.getOverlayInfosForTarget(targetPackageName, userId);
502 }
503 }
504
505 @Override
506 public OverlayInfo getOverlayInfo(@Nullable final String packageName,
507 int userId) throws RemoteException {
508 userId = handleIncomingUser(userId, "getOverlayInfo");
509 if (packageName == null) {
510 return null;
511 }
512
513 synchronized (mLock) {
514 return mImpl.getOverlayInfo(packageName, userId);
515 }
516 }
517
518 @Override
519 public boolean setEnabled(@Nullable final String packageName, final boolean enable,
520 int userId) throws RemoteException {
521 enforceChangeOverlayPackagesPermission("setEnabled");
522 userId = handleIncomingUser(userId, "setEnabled");
523 if (packageName == null) {
524 return false;
525 }
526
527 final long ident = Binder.clearCallingIdentity();
528 try {
529 synchronized (mLock) {
530 return mImpl.setEnabled(packageName, enable, userId);
531 }
532 } finally {
533 Binder.restoreCallingIdentity(ident);
534 }
535 }
536
537 @Override
Jason Monk929ed8d2017-03-07 16:01:20 -0500538 public boolean setEnabledExclusive(@Nullable final String packageName, final boolean enable,
539 int userId) throws RemoteException {
540 enforceChangeOverlayPackagesPermission("setEnabled");
541 userId = handleIncomingUser(userId, "setEnabled");
Adam Lesinskic745f422017-04-05 16:31:30 -0700542 if (packageName == null || !enable) {
Jason Monk929ed8d2017-03-07 16:01:20 -0500543 return false;
544 }
545
546 final long ident = Binder.clearCallingIdentity();
547 try {
548 synchronized (mLock) {
Adrian Roosc84df772018-01-19 21:20:22 +0100549 return mImpl.setEnabledExclusive(packageName, false /* withinCategory */,
550 userId);
551 }
552 } finally {
553 Binder.restoreCallingIdentity(ident);
554 }
555 }
556
557 @Override
558 public boolean setEnabledExclusiveInCategory(@Nullable String packageName, int userId)
559 throws RemoteException {
560 enforceChangeOverlayPackagesPermission("setEnabled");
561 userId = handleIncomingUser(userId, "setEnabled");
562 if (packageName == null) {
563 return false;
564 }
565
566 final long ident = Binder.clearCallingIdentity();
567 try {
568 synchronized (mLock) {
569 return mImpl.setEnabledExclusive(packageName, true /* withinCategory */,
570 userId);
Jason Monk929ed8d2017-03-07 16:01:20 -0500571 }
572 } finally {
573 Binder.restoreCallingIdentity(ident);
574 }
575 }
576
577 @Override
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100578 public boolean setPriority(@Nullable final String packageName,
579 @Nullable final String parentPackageName, int userId) throws RemoteException {
580 enforceChangeOverlayPackagesPermission("setPriority");
581 userId = handleIncomingUser(userId, "setPriority");
582 if (packageName == null || parentPackageName == null) {
583 return false;
584 }
585
586 final long ident = Binder.clearCallingIdentity();
587 try {
588 synchronized (mLock) {
589 return mImpl.setPriority(packageName, parentPackageName, userId);
590 }
591 } finally {
592 Binder.restoreCallingIdentity(ident);
593 }
594 }
595
596 @Override
597 public boolean setHighestPriority(@Nullable final String packageName, int userId)
598 throws RemoteException {
599 enforceChangeOverlayPackagesPermission("setHighestPriority");
600 userId = handleIncomingUser(userId, "setHighestPriority");
601 if (packageName == null) {
602 return false;
603 }
604
605 final long ident = Binder.clearCallingIdentity();
606 try {
607 synchronized (mLock) {
608 return mImpl.setHighestPriority(packageName, userId);
609 }
610 } finally {
611 Binder.restoreCallingIdentity(ident);
612 }
613 }
614
615 @Override
616 public boolean setLowestPriority(@Nullable final String packageName, int userId)
617 throws RemoteException {
618 enforceChangeOverlayPackagesPermission("setLowestPriority");
619 userId = handleIncomingUser(userId, "setLowestPriority");
620 if (packageName == null) {
621 return false;
622 }
623
624 final long ident = Binder.clearCallingIdentity();
625 try {
626 synchronized (mLock) {
627 return mImpl.setLowestPriority(packageName, userId);
628 }
629 } finally {
630 Binder.restoreCallingIdentity(ident);
631 }
632 }
633
634 @Override
635 public void onShellCommand(@NonNull final FileDescriptor in,
636 @NonNull final FileDescriptor out, @NonNull final FileDescriptor err,
637 @NonNull final String[] args, @NonNull final ShellCallback callback,
638 @NonNull final ResultReceiver resultReceiver) {
639 (new OverlayManagerShellCommand(this)).exec(
640 this, in, out, err, args, callback, resultReceiver);
641 }
642
643 @Override
644 protected void dump(@NonNull final FileDescriptor fd, @NonNull final PrintWriter pw,
645 @NonNull final String[] argv) {
646 enforceDumpPermission("dump");
647
648 final boolean verbose = argv.length > 0 && "--verbose".equals(argv[0]);
649
650 synchronized (mLock) {
651 mImpl.onDump(pw);
652 mPackageManager.dump(pw, verbose);
653 }
654 }
655
656 /**
657 * Ensure that the caller has permission to interact with the given userId.
658 * If the calling user is not the same as the provided user, the caller needs
659 * to hold the INTERACT_ACROSS_USERS_FULL permission (or be system uid or
660 * root).
661 *
662 * @param userId the user to interact with
663 * @param message message for any SecurityException
664 */
665 private int handleIncomingUser(final int userId, @NonNull final String message) {
666 return ActivityManager.handleIncomingUser(Binder.getCallingPid(),
667 Binder.getCallingUid(), userId, false, true, message, null);
668 }
669
670 /**
671 * Enforce that the caller holds the CHANGE_OVERLAY_PACKAGES permission (or is
672 * system or root).
673 *
674 * @param message used as message if SecurityException is thrown
675 * @throws SecurityException if the permission check fails
676 */
677 private void enforceChangeOverlayPackagesPermission(@NonNull final String message) {
678 getContext().enforceCallingOrSelfPermission(
679 android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, message);
680 }
681
682 /**
683 * Enforce that the caller holds the DUMP permission (or is system or root).
684 *
685 * @param message used as message if SecurityException is thrown
686 * @throws SecurityException if the permission check fails
687 */
688 private void enforceDumpPermission(@NonNull final String message) {
689 getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
690 message);
691 }
692 };
693
Adam Lesinskic745f422017-04-05 16:31:30 -0700694 private final class OverlayChangeListener
695 implements OverlayManagerServiceImpl.OverlayChangeListener {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100696 @Override
Adam Lesinskic745f422017-04-05 16:31:30 -0700697 public void onOverlaysChanged(@NonNull final String targetPackageName, final int userId) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100698 schedulePersistSettings();
Adam Lesinskic745f422017-04-05 16:31:30 -0700699 FgThread.getHandler().post(() -> {
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700700 updateAssets(userId, targetPackageName);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100701
Adam Lesinskic745f422017-04-05 16:31:30 -0700702 final Intent intent = new Intent(Intent.ACTION_OVERLAY_CHANGED,
703 Uri.fromParts("package", targetPackageName, null));
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100704 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Adam Lesinskic745f422017-04-05 16:31:30 -0700705
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100706 if (DEBUG) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700707 Slog.d(TAG, "send broadcast " + intent);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100708 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700709
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100710 try {
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200711 ActivityManager.getService().broadcastIntent(null, intent, null, null, 0,
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100712 null, null, null, android.app.AppOpsManager.OP_NONE, null, false, false,
713 userId);
714 } catch (RemoteException e) {
715 // Intentionally left empty.
716 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700717 });
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100718 }
719 }
720
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700721 /**
722 * Updates the target packages' set of enabled overlays in PackageManager.
723 */
724 private void updateOverlayPaths(int userId, List<String> targetPackageNames) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700725 if (DEBUG) {
726 Slog.d(TAG, "Updating overlay assets");
727 }
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200728 final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
729 final boolean updateFrameworkRes = targetPackageNames.contains("android");
730 if (updateFrameworkRes) {
731 targetPackageNames = pm.getTargetPackageNames(userId);
732 }
733
734 final Map<String, List<String>> pendingChanges = new ArrayMap<>(targetPackageNames.size());
735 synchronized (mLock) {
Todd Kennedy560830c2017-06-16 13:55:13 -0700736 final List<String> frameworkOverlays =
737 mImpl.getEnabledOverlayPackageNames("android", userId);
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200738 final int N = targetPackageNames.size();
739 for (int i = 0; i < N; i++) {
740 final String targetPackageName = targetPackageNames.get(i);
Todd Kennedy560830c2017-06-16 13:55:13 -0700741 List<String> list = new ArrayList<>();
742 if (!"android".equals(targetPackageName)) {
743 list.addAll(frameworkOverlays);
744 }
745 list.addAll(mImpl.getEnabledOverlayPackageNames(targetPackageName, userId));
746 pendingChanges.put(targetPackageName, list);
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200747 }
748 }
749
750 final int N = targetPackageNames.size();
751 for (int i = 0; i < N; i++) {
752 final String targetPackageName = targetPackageNames.get(i);
Adam Lesinskic745f422017-04-05 16:31:30 -0700753 if (DEBUG) {
754 Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=["
755 + TextUtils.join(",", pendingChanges.get(targetPackageName))
756 + "] userId=" + userId);
757 }
758
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200759 if (!pm.setEnabledOverlayPackages(
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700760 userId, targetPackageName, pendingChanges.get(targetPackageName))) {
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200761 Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700762 targetPackageName, userId));
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200763 }
764 }
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700765 }
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200766
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700767 private void updateAssets(final int userId, final String targetPackageName) {
768 updateAssets(userId, Collections.singletonList(targetPackageName));
769 }
770
771 private void updateAssets(final int userId, List<String> targetPackageNames) {
772 updateOverlayPaths(userId, targetPackageNames);
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200773 final IActivityManager am = ActivityManager.getService();
774 try {
775 am.scheduleApplicationInfoChanged(targetPackageNames, userId);
776 } catch (RemoteException e) {
777 // Intentionally left empty.
778 }
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100779 }
780
781 private void schedulePersistSettings() {
782 if (mPersistSettingsScheduled.getAndSet(true)) {
783 return;
784 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700785 IoThread.getHandler().post(() -> {
786 mPersistSettingsScheduled.set(false);
787 if (DEBUG) {
788 Slog.d(TAG, "Writing overlay settings");
789 }
790 synchronized (mLock) {
791 FileOutputStream stream = null;
792 try {
793 stream = mSettingsFile.startWrite();
794 mSettings.persist(stream);
795 mSettingsFile.finishWrite(stream);
796 } catch (IOException | XmlPullParserException e) {
797 mSettingsFile.failWrite(stream);
798 Slog.e(TAG, "failed to persist overlay state", e);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100799 }
800 }
801 });
802 }
803
804 private void restoreSettings() {
805 synchronized (mLock) {
806 if (!mSettingsFile.getBaseFile().exists()) {
807 return;
808 }
809 try (final FileInputStream stream = mSettingsFile.openRead()) {
810 mSettings.restore(stream);
811
812 // We might have data for dying users if the device was
813 // restarted before we received USER_REMOVED. Remove data for
814 // users that will not exist after the system is ready.
815
Adam Lesinskid11c5512017-04-11 12:01:10 -0700816 final List<UserInfo> liveUsers = mUserManager.getUsers(true /*excludeDying*/);
817 final int[] liveUserIds = new int[liveUsers.size()];
818 for (int i = 0; i < liveUsers.size(); i++) {
819 liveUserIds[i] = liveUsers.get(i).getUserHandle().getIdentifier();
820 }
821 Arrays.sort(liveUserIds);
822
823 for (int userId : mSettings.getUsers()) {
824 if (Arrays.binarySearch(liveUserIds, userId) < 0) {
825 mSettings.removeUser(userId);
826 }
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100827 }
828 } catch (IOException | XmlPullParserException e) {
829 Slog.e(TAG, "failed to restore overlay state", e);
830 }
831 }
832 }
833
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100834 private static final class PackageManagerHelper implements
835 OverlayManagerServiceImpl.PackageManagerHelper {
836
837 private final IPackageManager mPackageManager;
838 private final PackageManagerInternal mPackageManagerInternal;
839
840 // Use a cache for performance and for consistency within OMS: because
841 // additional PACKAGE_* intents may be delivered while we process an
842 // intent, querying the PackageManagerService for the actual current
843 // state may lead to contradictions within OMS. Better then to lag
844 // behind until all pending intents have been processed.
845 private final SparseArray<HashMap<String, PackageInfo>> mCache = new SparseArray<>();
846
847 PackageManagerHelper() {
848 mPackageManager = getPackageManager();
849 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
850 }
851
852 public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId,
853 final boolean useCache) {
854 if (useCache) {
855 final PackageInfo cachedPi = getCachedPackageInfo(packageName, userId);
856 if (cachedPi != null) {
857 return cachedPi;
858 }
859 }
860 try {
861 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0, userId);
862 if (useCache && pi != null) {
863 cachePackageInfo(packageName, userId, pi);
864 }
865 return pi;
866 } catch (RemoteException e) {
867 // Intentionally left empty.
868 }
869 return null;
870 }
871
872 @Override
873 public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId) {
874 return getPackageInfo(packageName, userId, true);
875 }
876
877 @Override
878 public boolean signaturesMatching(@NonNull final String packageName1,
879 @NonNull final String packageName2, final int userId) {
880 // The package manager does not support different versions of packages
881 // to be installed for different users: ignore userId for now.
882 try {
Adam Lesinskic745f422017-04-05 16:31:30 -0700883 return mPackageManager.checkSignatures(
884 packageName1, packageName2) == SIGNATURE_MATCH;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100885 } catch (RemoteException e) {
886 // Intentionally left blank
887 }
888 return false;
889 }
890
891 @Override
892 public List<PackageInfo> getOverlayPackages(final int userId) {
893 return mPackageManagerInternal.getOverlayPackages(userId);
894 }
895
896 public PackageInfo getCachedPackageInfo(@NonNull final String packageName,
897 final int userId) {
898 final HashMap<String, PackageInfo> map = mCache.get(userId);
899 return map == null ? null : map.get(packageName);
900 }
901
902 public void cachePackageInfo(@NonNull final String packageName, final int userId,
903 @NonNull final PackageInfo pi) {
904 HashMap<String, PackageInfo> map = mCache.get(userId);
905 if (map == null) {
906 map = new HashMap<>();
907 mCache.put(userId, map);
908 }
909 map.put(packageName, pi);
910 }
911
912 public void forgetPackageInfo(@NonNull final String packageName, final int userId) {
913 final HashMap<String, PackageInfo> map = mCache.get(userId);
914 if (map == null) {
915 return;
916 }
917 map.remove(packageName);
918 if (map.isEmpty()) {
919 mCache.delete(userId);
920 }
921 }
922
923 public void forgetAllPackageInfos(final int userId) {
924 mCache.delete(userId);
925 }
926
927 private static final String TAB1 = " ";
928 private static final String TAB2 = TAB1 + TAB1;
929
930 public void dump(@NonNull final PrintWriter pw, final boolean verbose) {
931 pw.println("PackageInfo cache");
932
933 if (!verbose) {
934 int count = 0;
935 final int N = mCache.size();
936 for (int i = 0; i < N; i++) {
937 final int userId = mCache.keyAt(i);
938 count += mCache.get(userId).size();
939 }
940 pw.println(TAB1 + count + " package(s)");
941 return;
942 }
943
944 if (mCache.size() == 0) {
945 pw.println(TAB1 + "<empty>");
946 return;
947 }
948
949 final int N = mCache.size();
950 for (int i = 0; i < N; i++) {
951 final int userId = mCache.keyAt(i);
952 pw.println(TAB1 + "User " + userId);
953 final HashMap<String, PackageInfo> map = mCache.get(userId);
954 for (Map.Entry<String, PackageInfo> entry : map.entrySet()) {
955 pw.println(TAB2 + entry.getKey() + ": " + entry.getValue());
956 }
957 }
958 }
959 }
960}