blob: 019c9528f8abcdf742a975c9dfce71d93b1eb995 [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.content.om.OverlayInfo.STATE_DISABLED;
20import static android.content.om.OverlayInfo.STATE_ENABLED;
Mårten Kongstada525e222018-04-10 16:57:33 +020021import static android.content.om.OverlayInfo.STATE_ENABLED_STATIC;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010022import static android.content.om.OverlayInfo.STATE_MISSING_TARGET;
23import static android.content.om.OverlayInfo.STATE_NO_IDMAP;
Mårten Kongstad15a0ac02019-03-26 10:30:08 +010024import static android.content.om.OverlayInfo.STATE_OVERLAY_IS_BEING_REPLACED;
25import static android.content.om.OverlayInfo.STATE_TARGET_IS_BEING_REPLACED;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010026
27import static com.android.server.om.OverlayManagerService.DEBUG;
28import static com.android.server.om.OverlayManagerService.TAG;
29
30import android.annotation.NonNull;
31import android.annotation.Nullable;
32import android.content.om.OverlayInfo;
Winsone0b984e2019-02-13 16:20:33 -080033import android.content.pm.ApplicationInfo;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010034import android.content.pm.PackageInfo;
Adam Lesinskia5ca6242017-03-01 15:45:12 -080035import android.text.TextUtils;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010036import android.util.ArrayMap;
37import android.util.ArraySet;
38import android.util.Slog;
39
Winsone0b984e2019-02-13 16:20:33 -080040import com.android.internal.util.ArrayUtils;
41
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010042import java.io.PrintWriter;
43import java.util.ArrayList;
44import java.util.Iterator;
45import java.util.List;
46import java.util.Map;
Narayan Kamath607223f2018-02-19 14:09:02 +000047import java.util.Objects;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010048import java.util.Set;
49
50/**
51 * Internal implementation of OverlayManagerService.
52 *
53 * Methods in this class should only be called by the OverlayManagerService.
54 * This class is not thread-safe; the caller is expected to ensure the
55 * necessary thread synchronization.
56 *
57 * @see OverlayManagerService
58 */
59final class OverlayManagerServiceImpl {
Winsone0b984e2019-02-13 16:20:33 -080060 /**
61 * @deprecated Not used. See {@link android.content.om.OverlayInfo#STATE_TARGET_UPGRADING}.
62 */
63 @Deprecated
Mårten Kongstad15a0ac02019-03-26 10:30:08 +010064 private static final int FLAG_TARGET_IS_BEING_REPLACED = 1 << 0;
Winsone0b984e2019-02-13 16:20:33 -080065
66 // Flags to use in conjunction with updateState.
Mårten Kongstad15a0ac02019-03-26 10:30:08 +010067 private static final int FLAG_OVERLAY_IS_BEING_REPLACED = 1 << 1;
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +010068
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010069 private final PackageManagerHelper mPackageManager;
70 private final IdmapManager mIdmapManager;
71 private final OverlayManagerSettings mSettings;
Adam Lesinski7b031812018-02-22 13:32:53 -080072 private final String[] mDefaultOverlays;
Adam Lesinskic745f422017-04-05 16:31:30 -070073 private final OverlayChangeListener mListener;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010074
Mårten Kongstad2f1944b2018-04-10 17:44:42 +020075 /**
76 * Helper method to merge the overlay manager's (as read from overlays.xml)
77 * and package manager's (as parsed from AndroidManifest.xml files) views
78 * on overlays.
79 *
80 * Both managers are usually in agreement, but especially after an OTA things
81 * may differ. The package manager is always providing the truth; the overlay
82 * manager has to adapt. Depending on what has changed about an overlay, we
83 * should either scrap the overlay manager's previous settings or merge the old
84 * settings with the new.
85 */
86 private static boolean mustReinitializeOverlay(@NonNull final PackageInfo theTruth,
87 @Nullable final OverlayInfo oldSettings) {
88 if (oldSettings == null) {
89 return true;
90 }
91 if (!Objects.equals(theTruth.overlayTarget, oldSettings.targetPackageName)) {
92 return true;
93 }
Ryan Mitchelld57fb1f2019-03-20 17:18:58 -070094 if (!Objects.equals(theTruth.targetOverlayableName, oldSettings.targetOverlayableName)) {
95 return true;
96 }
Mårten Kongstad2f1944b2018-04-10 17:44:42 +020097 if (theTruth.isStaticOverlayPackage() != oldSettings.isStatic) {
98 return true;
99 }
100 // a change in priority is only relevant for static RROs: specifically,
101 // a regular RRO should not have its state reset only because a change
102 // in priority
Mårten Kongstad38988342018-12-04 10:28:01 +0100103 if (theTruth.isStaticOverlayPackage()
104 && theTruth.overlayPriority != oldSettings.priority) {
Mårten Kongstad2f1944b2018-04-10 17:44:42 +0200105 return true;
106 }
107 return false;
108 }
109
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100110 OverlayManagerServiceImpl(@NonNull final PackageManagerHelper packageManager,
111 @NonNull final IdmapManager idmapManager,
Adam Lesinskia5ca6242017-03-01 15:45:12 -0800112 @NonNull final OverlayManagerSettings settings,
Adam Lesinski7b031812018-02-22 13:32:53 -0800113 @NonNull final String[] defaultOverlays,
Adam Lesinskic745f422017-04-05 16:31:30 -0700114 @NonNull final OverlayChangeListener listener) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100115 mPackageManager = packageManager;
116 mIdmapManager = idmapManager;
117 mSettings = settings;
Adam Lesinskia5ca6242017-03-01 15:45:12 -0800118 mDefaultOverlays = defaultOverlays;
Adam Lesinskic745f422017-04-05 16:31:30 -0700119 mListener = listener;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100120 }
121
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700122 /**
123 * Call this to synchronize the Settings for a user with what PackageManager knows about a user.
124 * Returns a list of target packages that must refresh their overlays. This list is the union
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100125 * of two sets: the set of targets with currently active overlays, and the
126 * set of targets that had, but no longer have, active overlays.
127 */
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700128 ArrayList<String> updateOverlaysForUser(final int newUserId) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100129 if (DEBUG) {
Adam Lesinskiada8deb2017-05-12 13:50:42 -0700130 Slog.d(TAG, "updateOverlaysForUser newUserId=" + newUserId);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100131 }
132
133 final Set<String> packagesToUpdateAssets = new ArraySet<>();
134 final ArrayMap<String, List<OverlayInfo>> tmp = mSettings.getOverlaysForUser(newUserId);
135 final int tmpSize = tmp.size();
136 final ArrayMap<String, OverlayInfo> storedOverlayInfos = new ArrayMap<>(tmpSize);
137 for (int i = 0; i < tmpSize; i++) {
138 final List<OverlayInfo> chunk = tmp.valueAt(i);
139 final int chunkSize = chunk.size();
140 for (int j = 0; j < chunkSize; j++) {
141 final OverlayInfo oi = chunk.get(j);
142 storedOverlayInfos.put(oi.packageName, oi);
143 }
144 }
145
Mårten Kongstad2f1944b2018-04-10 17:44:42 +0200146 // Reset overlays if something critical like the target package name
147 // has changed
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100148 List<PackageInfo> overlayPackages = mPackageManager.getOverlayPackages(newUserId);
149 final int overlayPackagesSize = overlayPackages.size();
150 for (int i = 0; i < overlayPackagesSize; i++) {
151 final PackageInfo overlayPackage = overlayPackages.get(i);
152 final OverlayInfo oi = storedOverlayInfos.get(overlayPackage.packageName);
Mårten Kongstad2f1944b2018-04-10 17:44:42 +0200153
154 if (mustReinitializeOverlay(overlayPackage, oi)) {
155 // if targetPackageName has changed the package that *used* to
156 // be the target must also update its assets
157 if (oi != null) {
158 packagesToUpdateAssets.add(oi.targetPackageName);
159 }
160
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100161 mSettings.init(overlayPackage.packageName, newUserId,
162 overlayPackage.overlayTarget,
Ryan Mitchelld57fb1f2019-03-20 17:18:58 -0700163 overlayPackage.targetOverlayableName,
Jaekyun Seok42d53f62017-04-10 13:48:58 +0900164 overlayPackage.applicationInfo.getBaseCodePath(),
Adam Lesinski7b031812018-02-22 13:32:53 -0800165 overlayPackage.isStaticOverlayPackage(),
166 overlayPackage.overlayPriority,
Adrian Roosc84df772018-01-19 21:20:22 +0100167 overlayPackage.overlayCategory);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100168 }
169
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100170 storedOverlayInfos.remove(overlayPackage.packageName);
171 }
172
173 // any OverlayInfo left in storedOverlayInfos is no longer
174 // installed and should be removed
175 final int storedOverlayInfosSize = storedOverlayInfos.size();
176 for (int i = 0; i < storedOverlayInfosSize; i++) {
Mårten Kongstadc0bba8b2017-01-27 10:15:49 +0100177 final OverlayInfo oi = storedOverlayInfos.valueAt(i);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100178 mSettings.remove(oi.packageName, oi.userId);
179 removeIdmapIfPossible(oi);
180 packagesToUpdateAssets.add(oi.targetPackageName);
181 }
182
Mårten Kongstad2f1944b2018-04-10 17:44:42 +0200183 // make sure every overlay's state is up-to-date; this needs to happen
184 // after old overlays have been removed, or we risk removing a
185 // legitimate idmap file if a new overlay package has the same apk path
186 // as the removed overlay package used to have
187 for (int i = 0; i < overlayPackagesSize; i++) {
188 final PackageInfo overlayPackage = overlayPackages.get(i);
189 try {
190 updateState(overlayPackage.overlayTarget, overlayPackage.packageName,
191 newUserId, 0);
192 } catch (OverlayManagerSettings.BadKeyException e) {
193 Slog.e(TAG, "failed to update settings", e);
194 mSettings.remove(overlayPackage.packageName, newUserId);
195 }
196 packagesToUpdateAssets.add(overlayPackage.overlayTarget);
197 }
198
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100199 // remove target packages that are not installed
200 final Iterator<String> iter = packagesToUpdateAssets.iterator();
201 while (iter.hasNext()) {
202 String targetPackageName = iter.next();
203 if (mPackageManager.getPackageInfo(targetPackageName, newUserId) == null) {
204 iter.remove();
205 }
206 }
Adam Lesinski7b031812018-02-22 13:32:53 -0800207
208 // Collect all of the categories in which we have at least one overlay enabled.
209 final ArraySet<String> enabledCategories = new ArraySet<>();
210 final ArrayMap<String, List<OverlayInfo>> userOverlays =
211 mSettings.getOverlaysForUser(newUserId);
212 final int userOverlayTargetCount = userOverlays.size();
213 for (int i = 0; i < userOverlayTargetCount; i++) {
214 final List<OverlayInfo> overlayList = userOverlays.valueAt(i);
215 final int overlayCount = overlayList != null ? overlayList.size() : 0;
216 for (int j = 0; j < overlayCount; j++) {
217 final OverlayInfo oi = overlayList.get(j);
218 if (oi.isEnabled()) {
219 enabledCategories.add(oi.category);
220 }
221 }
222 }
223
224 // Enable the default overlay if its category does not have a single overlay enabled.
225 for (final String defaultOverlay : mDefaultOverlays) {
226 try {
227 final OverlayInfo oi = mSettings.getOverlayInfo(defaultOverlay, newUserId);
228 if (!enabledCategories.contains(oi.category)) {
229 Slog.w(TAG, "Enabling default overlay '" + defaultOverlay + "' for target '"
230 + oi.targetPackageName + "' in category '" + oi.category + "' for user "
231 + newUserId);
232 mSettings.setEnabled(oi.packageName, newUserId, true);
233 if (updateState(oi.targetPackageName, oi.packageName, newUserId, 0)) {
234 packagesToUpdateAssets.add(oi.targetPackageName);
235 }
236 }
237 } catch (OverlayManagerSettings.BadKeyException e) {
238 Slog.e(TAG, "Failed to set default overlay '" + defaultOverlay + "' for user "
239 + newUserId, e);
240 }
241 }
242
Adam Lesinskia5ca6242017-03-01 15:45:12 -0800243 return new ArrayList<>(packagesToUpdateAssets);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100244 }
245
246 void onUserRemoved(final int userId) {
247 if (DEBUG) {
248 Slog.d(TAG, "onUserRemoved userId=" + userId);
249 }
250 mSettings.removeUser(userId);
251 }
252
253 void onTargetPackageAdded(@NonNull final String packageName, final int userId) {
254 if (DEBUG) {
255 Slog.d(TAG, "onTargetPackageAdded packageName=" + packageName + " userId=" + userId);
256 }
257
Winsone0b984e2019-02-13 16:20:33 -0800258 updateAndRefreshOverlaysForTarget(packageName, userId, 0);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100259 }
260
Ryan Mitchelld41d0db2018-05-09 09:01:12 -0700261 void onTargetPackageChanged(@NonNull final String packageName, final int userId) {
262 if (DEBUG) {
263 Slog.d(TAG, "onTargetPackageChanged packageName=" + packageName + " userId=" + userId);
264 }
265
Winsone0b984e2019-02-13 16:20:33 -0800266 updateAndRefreshOverlaysForTarget(packageName, userId, 0);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100267 }
268
Mårten Kongstad15a0ac02019-03-26 10:30:08 +0100269 void onTargetPackageReplacing(@NonNull final String packageName, final int userId) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100270 if (DEBUG) {
Mårten Kongstad15a0ac02019-03-26 10:30:08 +0100271 Slog.d(TAG, "onTargetPackageReplacing packageName=" + packageName + " userId="
272 + userId);
273 }
274
275 updateAndRefreshOverlaysForTarget(packageName, userId, 0);
276 }
277
278 void onTargetPackageReplaced(@NonNull final String packageName, final int userId) {
279 if (DEBUG) {
280 Slog.d(TAG, "onTargetPackageReplaced packageName=" + packageName + " userId=" + userId);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100281 }
282
Winsone0b984e2019-02-13 16:20:33 -0800283 updateAndRefreshOverlaysForTarget(packageName, userId, 0);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100284 }
285
286 void onTargetPackageRemoved(@NonNull final String packageName, final int userId) {
287 if (DEBUG) {
288 Slog.d(TAG, "onTargetPackageRemoved packageName=" + packageName + " userId=" + userId);
289 }
290
Winsone0b984e2019-02-13 16:20:33 -0800291 updateAndRefreshOverlaysForTarget(packageName, userId, 0);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100292 }
293
Adam Lesinskic745f422017-04-05 16:31:30 -0700294 /**
Mårten Kongstada3bd3492018-02-20 10:02:17 +0100295 * Update the state of any overlays for this target.
Adam Lesinskic745f422017-04-05 16:31:30 -0700296 */
Winsone0b984e2019-02-13 16:20:33 -0800297 private void updateAndRefreshOverlaysForTarget(@NonNull final String targetPackageName,
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100298 final int userId, final int flags) {
Ryan Mitchell8987e832019-07-23 10:01:06 -0700299 final List<OverlayInfo> targetOverlays = mSettings.getOverlaysForTarget(targetPackageName,
300 userId);
Winsone0b984e2019-02-13 16:20:33 -0800301
Ryan Mitchell8987e832019-07-23 10:01:06 -0700302 // Update the state for any overlay that targets this package.
Mårten Kongstad497945c2018-04-27 09:56:13 +0200303 boolean modified = false;
Ryan Mitchell8987e832019-07-23 10:01:06 -0700304 for (final OverlayInfo oi : targetOverlays) {
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100305 final PackageInfo overlayPackage = mPackageManager.getPackageInfo(oi.packageName,
306 userId);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100307 if (overlayPackage == null) {
Mårten Kongstad497945c2018-04-27 09:56:13 +0200308 modified |= mSettings.remove(oi.packageName, oi.userId);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100309 removeIdmapIfPossible(oi);
310 } else {
311 try {
Mårten Kongstad497945c2018-04-27 09:56:13 +0200312 modified |= updateState(targetPackageName, oi.packageName, userId, flags);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100313 } catch (OverlayManagerSettings.BadKeyException e) {
314 Slog.e(TAG, "failed to update settings", e);
Mårten Kongstad497945c2018-04-27 09:56:13 +0200315 modified |= mSettings.remove(oi.packageName, userId);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100316 }
317 }
318 }
Mårten Kongstada3bd3492018-02-20 10:02:17 +0100319
Winsone0b984e2019-02-13 16:20:33 -0800320 if (!modified) {
Ryan Mitchell8987e832019-07-23 10:01:06 -0700321 // Update the overlay paths of the target within package manager if necessary.
322 final List<String> enabledOverlayPaths = new ArrayList<>(targetOverlays.size());
323
324 // Framework overlays are first in the overlay paths of a package within PackageManager.
325 for (final OverlayInfo oi : mSettings.getOverlaysForTarget("android", userId)) {
326 if (oi.isEnabled()) {
327 enabledOverlayPaths.add(oi.baseCodePath);
328 }
329 }
330
331 for (final OverlayInfo oi : targetOverlays) {
332 if (oi.isEnabled()) {
333 enabledOverlayPaths.add(oi.baseCodePath);
334 }
335 }
336
337 // TODO(): Use getEnabledOverlayPaths(userId, targetPackageName) instead of
338 // resourceDirs if in the future resourceDirs contains APKs other than overlays
Winsone0b984e2019-02-13 16:20:33 -0800339 PackageInfo packageInfo = mPackageManager.getPackageInfo(targetPackageName, userId);
340 ApplicationInfo appInfo = packageInfo == null ? null : packageInfo.applicationInfo;
341 String[] resourceDirs = appInfo == null ? null : appInfo.resourceDirs;
Mårten Kongstada3bd3492018-02-20 10:02:17 +0100342
Winsone0b984e2019-02-13 16:20:33 -0800343 // If the lists aren't the same length, the enabled overlays have changed
Ryan Mitchell8987e832019-07-23 10:01:06 -0700344 if (ArrayUtils.size(resourceDirs) != enabledOverlayPaths.size()) {
Winsone0b984e2019-02-13 16:20:33 -0800345 modified = true;
346 } else if (resourceDirs != null) {
347 // If any element isn't equal, an overlay or the order of overlays has changed
348 for (int index = 0; index < resourceDirs.length; index++) {
Ryan Mitchell8987e832019-07-23 10:01:06 -0700349 if (!resourceDirs[index].equals(enabledOverlayPaths.get(index))) {
Winsone0b984e2019-02-13 16:20:33 -0800350 modified = true;
351 break;
352 }
353 }
354 }
355 }
356
357 if (modified) {
358 mListener.onOverlaysChanged(targetPackageName, userId);
359 }
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100360 }
361
362 void onOverlayPackageAdded(@NonNull final String packageName, final int userId) {
363 if (DEBUG) {
364 Slog.d(TAG, "onOverlayPackageAdded packageName=" + packageName + " userId=" + userId);
365 }
366
367 final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
368 if (overlayPackage == null) {
369 Slog.w(TAG, "overlay package " + packageName + " was added, but couldn't be found");
370 onOverlayPackageRemoved(packageName, userId);
371 return;
372 }
373
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100374 mSettings.init(packageName, userId, overlayPackage.overlayTarget,
Ryan Mitchelld57fb1f2019-03-20 17:18:58 -0700375 overlayPackage.targetOverlayableName,
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800376 overlayPackage.applicationInfo.getBaseCodePath(),
Adrian Roosc84df772018-01-19 21:20:22 +0100377 overlayPackage.isStaticOverlayPackage(), overlayPackage.overlayPriority,
378 overlayPackage.overlayCategory);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100379 try {
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100380 if (updateState(overlayPackage.overlayTarget, packageName, userId, 0)) {
Mårten Kongstad497945c2018-04-27 09:56:13 +0200381 mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
Adam Lesinskic745f422017-04-05 16:31:30 -0700382 }
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100383 } catch (OverlayManagerSettings.BadKeyException e) {
384 Slog.e(TAG, "failed to update settings", e);
385 mSettings.remove(packageName, userId);
386 }
387 }
388
389 void onOverlayPackageChanged(@NonNull final String packageName, final int userId) {
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100390 if (DEBUG) {
391 Slog.d(TAG, "onOverlayPackageChanged packageName=" + packageName + " userId=" + userId);
392 }
393
394 try {
395 final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
396 if (updateState(oi.targetPackageName, packageName, userId, 0)) {
Mårten Kongstad497945c2018-04-27 09:56:13 +0200397 mListener.onOverlaysChanged(oi.targetPackageName, userId);
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100398 }
399 } catch (OverlayManagerSettings.BadKeyException e) {
400 Slog.e(TAG, "failed to update settings", e);
401 }
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100402 }
403
Mårten Kongstad15a0ac02019-03-26 10:30:08 +0100404 void onOverlayPackageReplacing(@NonNull final String packageName, final int userId) {
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100405 if (DEBUG) {
Mårten Kongstad15a0ac02019-03-26 10:30:08 +0100406 Slog.d(TAG, "onOverlayPackageReplacing packageName=" + packageName + " userId="
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100407 + userId);
408 }
409
410 try {
411 final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
Mårten Kongstad15a0ac02019-03-26 10:30:08 +0100412 if (updateState(oi.targetPackageName, packageName, userId,
413 FLAG_OVERLAY_IS_BEING_REPLACED)) {
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100414 removeIdmapIfPossible(oi);
Mårten Kongstad497945c2018-04-27 09:56:13 +0200415 mListener.onOverlaysChanged(oi.targetPackageName, userId);
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100416 }
417 } catch (OverlayManagerSettings.BadKeyException e) {
418 Slog.e(TAG, "failed to update settings", e);
419 }
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100420 }
421
Mårten Kongstad15a0ac02019-03-26 10:30:08 +0100422 void onOverlayPackageReplaced(@NonNull final String packageName, final int userId) {
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100423 if (DEBUG) {
Mårten Kongstad15a0ac02019-03-26 10:30:08 +0100424 Slog.d(TAG, "onOverlayPackageReplaced packageName=" + packageName + " userId="
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100425 + userId);
426 }
427
428 final PackageInfo pkg = mPackageManager.getPackageInfo(packageName, userId);
429 if (pkg == null) {
Mårten Kongstad15a0ac02019-03-26 10:30:08 +0100430 Slog.w(TAG, "overlay package " + packageName + " was replaced, but couldn't be found");
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100431 onOverlayPackageRemoved(packageName, userId);
432 return;
433 }
434
435 try {
436 final OverlayInfo oldOi = mSettings.getOverlayInfo(packageName, userId);
Mårten Kongstad2f1944b2018-04-10 17:44:42 +0200437 if (mustReinitializeOverlay(pkg, oldOi)) {
438 if (oldOi != null && !oldOi.targetPackageName.equals(pkg.overlayTarget)) {
439 mListener.onOverlaysChanged(pkg.overlayTarget, userId);
440 }
Ryan Mitchelld57fb1f2019-03-20 17:18:58 -0700441 mSettings.init(packageName, userId, pkg.overlayTarget, pkg.targetOverlayableName,
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100442 pkg.applicationInfo.getBaseCodePath(), pkg.isStaticOverlayPackage(),
Adrian Roosc84df772018-01-19 21:20:22 +0100443 pkg.overlayPriority, pkg.overlayCategory);
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100444 }
445
446 if (updateState(pkg.overlayTarget, packageName, userId, 0)) {
Mårten Kongstad497945c2018-04-27 09:56:13 +0200447 mListener.onOverlaysChanged(pkg.overlayTarget, userId);
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100448 }
449 } catch (OverlayManagerSettings.BadKeyException e) {
450 Slog.e(TAG, "failed to update settings", e);
451 }
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100452 }
453
454 void onOverlayPackageRemoved(@NonNull final String packageName, final int userId) {
Adam Lesinskib67fc5f2018-01-19 16:15:11 -0800455 try {
456 final OverlayInfo overlayInfo = mSettings.getOverlayInfo(packageName, userId);
457 if (mSettings.remove(packageName, userId)) {
458 removeIdmapIfPossible(overlayInfo);
Mårten Kongstad44bdc882019-03-27 09:47:28 +0100459 mListener.onOverlaysChanged(overlayInfo.targetPackageName, userId);
Adam Lesinskib67fc5f2018-01-19 16:15:11 -0800460 }
461 } catch (OverlayManagerSettings.BadKeyException e) {
462 Slog.e(TAG, "failed to remove overlay", e);
463 }
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100464 }
465
466 OverlayInfo getOverlayInfo(@NonNull final String packageName, final int userId) {
467 try {
468 return mSettings.getOverlayInfo(packageName, userId);
469 } catch (OverlayManagerSettings.BadKeyException e) {
470 return null;
471 }
472 }
473
474 List<OverlayInfo> getOverlayInfosForTarget(@NonNull final String targetPackageName,
475 final int userId) {
476 return mSettings.getOverlaysForTarget(targetPackageName, userId);
477 }
478
479 Map<String, List<OverlayInfo>> getOverlaysForUser(final int userId) {
480 return mSettings.getOverlaysForUser(userId);
481 }
482
483 boolean setEnabled(@NonNull final String packageName, final boolean enable,
484 final int userId) {
485 if (DEBUG) {
486 Slog.d(TAG, String.format("setEnabled packageName=%s enable=%s userId=%d",
487 packageName, enable, userId));
488 }
489
490 final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
491 if (overlayPackage == null) {
492 return false;
493 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700494
495 // Ignore static overlays.
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800496 if (overlayPackage.isStaticOverlayPackage()) {
Jaekyun Seok04342892017-03-02 15:24:19 +0900497 return false;
498 }
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100499
500 try {
501 final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
Adam Lesinskic745f422017-04-05 16:31:30 -0700502 boolean modified = mSettings.setEnabled(packageName, userId, enable);
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100503 modified |= updateState(oi.targetPackageName, oi.packageName, userId, 0);
Adam Lesinskic745f422017-04-05 16:31:30 -0700504
505 if (modified) {
Mårten Kongstad497945c2018-04-27 09:56:13 +0200506 mListener.onOverlaysChanged(oi.targetPackageName, userId);
Adam Lesinskic745f422017-04-05 16:31:30 -0700507 }
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100508 return true;
509 } catch (OverlayManagerSettings.BadKeyException e) {
510 return false;
511 }
512 }
513
Adrian Roosc84df772018-01-19 21:20:22 +0100514 boolean setEnabledExclusive(@NonNull final String packageName, boolean withinCategory,
515 final int userId) {
Jason Monk929ed8d2017-03-07 16:01:20 -0500516 if (DEBUG) {
Adrian Roosc84df772018-01-19 21:20:22 +0100517 Slog.d(TAG, String.format("setEnabledExclusive packageName=%s"
518 + " withinCategory=%s userId=%d", packageName, withinCategory, userId));
Jason Monk929ed8d2017-03-07 16:01:20 -0500519 }
520
521 final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
522 if (overlayPackage == null) {
523 return false;
524 }
525
526 try {
527 final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100528 final String targetPackageName = oi.targetPackageName;
Adam Lesinskic745f422017-04-05 16:31:30 -0700529
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100530 List<OverlayInfo> allOverlays = getOverlayInfosForTarget(targetPackageName, userId);
Jason Monk929ed8d2017-03-07 16:01:20 -0500531
Adam Lesinskic745f422017-04-05 16:31:30 -0700532 boolean modified = false;
533
Jason Monk929ed8d2017-03-07 16:01:20 -0500534 // Disable all other overlays.
535 allOverlays.remove(oi);
536 for (int i = 0; i < allOverlays.size(); i++) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700537 final String disabledOverlayPackageName = allOverlays.get(i).packageName;
538 final PackageInfo disabledOverlayPackageInfo = mPackageManager.getPackageInfo(
539 disabledOverlayPackageName, userId);
540 if (disabledOverlayPackageInfo == null) {
541 modified |= mSettings.remove(disabledOverlayPackageName, userId);
542 continue;
543 }
544
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800545 if (disabledOverlayPackageInfo.isStaticOverlayPackage()) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700546 // Don't touch static overlays.
547 continue;
548 }
Narayan Kamath607223f2018-02-19 14:09:02 +0000549 if (withinCategory && !Objects.equals(disabledOverlayPackageInfo.overlayCategory,
Adrian Roosc84df772018-01-19 21:20:22 +0100550 oi.category)) {
551 // Don't touch overlays from other categories.
552 continue;
553 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700554
555 // Disable the overlay.
556 modified |= mSettings.setEnabled(disabledOverlayPackageName, userId, false);
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100557 modified |= updateState(targetPackageName, disabledOverlayPackageName, userId, 0);
Jason Monk929ed8d2017-03-07 16:01:20 -0500558 }
559
Adam Lesinskic745f422017-04-05 16:31:30 -0700560 // Enable the selected overlay.
561 modified |= mSettings.setEnabled(packageName, userId, true);
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100562 modified |= updateState(targetPackageName, packageName, userId, 0);
Adam Lesinskic745f422017-04-05 16:31:30 -0700563
564 if (modified) {
Mårten Kongstad497945c2018-04-27 09:56:13 +0200565 mListener.onOverlaysChanged(targetPackageName, userId);
Adam Lesinskic745f422017-04-05 16:31:30 -0700566 }
Jason Monk929ed8d2017-03-07 16:01:20 -0500567 return true;
568 } catch (OverlayManagerSettings.BadKeyException e) {
569 return false;
570 }
571 }
572
Adam Lesinskic745f422017-04-05 16:31:30 -0700573 private boolean isPackageUpdatableOverlay(@NonNull final String packageName, final int userId) {
Jaekyun Seok04342892017-03-02 15:24:19 +0900574 final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800575 if (overlayPackage == null || overlayPackage.isStaticOverlayPackage()) {
Jaekyun Seok04342892017-03-02 15:24:19 +0900576 return false;
577 }
578 return true;
579 }
580
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100581 boolean setPriority(@NonNull final String packageName,
582 @NonNull final String newParentPackageName, final int userId) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700583 if (DEBUG) {
584 Slog.d(TAG, "setPriority packageName=" + packageName + " newParentPackageName="
585 + newParentPackageName + " userId=" + userId);
586 }
587
588 if (!isPackageUpdatableOverlay(packageName, userId)) {
589 return false;
590 }
591
592 final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
593 if (overlayPackage == null) {
594 return false;
595 }
596
597 if (mSettings.setPriority(packageName, newParentPackageName, userId)) {
Mårten Kongstad497945c2018-04-27 09:56:13 +0200598 mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
Adam Lesinskic745f422017-04-05 16:31:30 -0700599 }
600 return true;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100601 }
602
603 boolean setHighestPriority(@NonNull final String packageName, final int userId) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700604 if (DEBUG) {
605 Slog.d(TAG, "setHighestPriority packageName=" + packageName + " userId=" + userId);
606 }
607
608 if (!isPackageUpdatableOverlay(packageName, userId)) {
609 return false;
610 }
611
612 final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
613 if (overlayPackage == null) {
614 return false;
615 }
616
617 if (mSettings.setHighestPriority(packageName, userId)) {
Mårten Kongstad497945c2018-04-27 09:56:13 +0200618 mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
Adam Lesinskic745f422017-04-05 16:31:30 -0700619 }
620 return true;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100621 }
622
623 boolean setLowestPriority(@NonNull final String packageName, final int userId) {
Adam Lesinskic745f422017-04-05 16:31:30 -0700624 if (DEBUG) {
625 Slog.d(TAG, "setLowestPriority packageName=" + packageName + " userId=" + userId);
626 }
627
628 if (!isPackageUpdatableOverlay(packageName, userId)) {
629 return false;
630 }
631
632 final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
633 if (overlayPackage == null) {
634 return false;
635 }
636
637 if (mSettings.setLowestPriority(packageName, userId)) {
Mårten Kongstad497945c2018-04-27 09:56:13 +0200638 mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
Adam Lesinskic745f422017-04-05 16:31:30 -0700639 }
640 return true;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100641 }
642
Mårten Kongstada465aec2019-04-12 12:32:41 +0200643 void dump(@NonNull final PrintWriter pw, @NonNull DumpState dumpState) {
644 mSettings.dump(pw, dumpState);
645 if (dumpState.getPackageName() == null) {
646 pw.println("Default overlays: " + TextUtils.join(";", mDefaultOverlays));
647 }
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100648 }
649
Winson Chung43f311e2019-04-29 12:57:21 -0700650 @NonNull String[] getDefaultOverlayPackages() {
651 return mDefaultOverlays;
652 }
653
Ryan Mitchell4043ca72019-06-03 16:11:24 -0700654 void removeIdmapForOverlay(String packageName, int userId) {
655 final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
656 removeIdmapIfPossible(oi);
657 }
658
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100659 List<String> getEnabledOverlayPackageNames(@NonNull final String targetPackageName,
660 final int userId) {
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100661 final List<OverlayInfo> overlays = mSettings.getOverlaysForTarget(targetPackageName,
662 userId);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100663 final List<String> paths = new ArrayList<>(overlays.size());
Mårten Kongstad38988342018-12-04 10:28:01 +0100664 final int n = overlays.size();
665 for (int i = 0; i < n; i++) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100666 final OverlayInfo oi = overlays.get(i);
667 if (oi.isEnabled()) {
668 paths.add(oi.packageName);
669 }
670 }
671 return paths;
672 }
673
Adam Lesinskic745f422017-04-05 16:31:30 -0700674 /**
675 * Returns true if the settings/state was modified, false otherwise.
676 */
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100677 private boolean updateState(@NonNull final String targetPackageName,
678 @NonNull final String overlayPackageName, final int userId, final int flags)
Adam Lesinskic745f422017-04-05 16:31:30 -0700679 throws OverlayManagerSettings.BadKeyException {
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100680
681 final PackageInfo targetPackage = mPackageManager.getPackageInfo(targetPackageName, userId);
682 final PackageInfo overlayPackage = mPackageManager.getPackageInfo(overlayPackageName,
683 userId);
684
Jaekyun Seok04342892017-03-02 15:24:19 +0900685 // Static RROs targeting to "android", ie framework-res.apk, are handled by native layers.
Mårten Kongstad38988342018-12-04 10:28:01 +0100686 if (targetPackage != null && overlayPackage != null
687 && !("android".equals(targetPackageName)
Adam Lesinskiab56b9d2017-11-14 00:50:18 -0800688 && overlayPackage.isStaticOverlayPackage())) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100689 mIdmapManager.createIdmap(targetPackage, overlayPackage, userId);
690 }
691
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100692 boolean modified = false;
693 if (overlayPackage != null) {
694 modified |= mSettings.setBaseCodePath(overlayPackageName, userId,
695 overlayPackage.applicationInfo.getBaseCodePath());
Mårten Kongstad2f1944b2018-04-10 17:44:42 +0200696 modified |= mSettings.setCategory(overlayPackageName, userId,
697 overlayPackage.overlayCategory);
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100698 }
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100699
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100700 final @OverlayInfo.State int currentState = mSettings.getState(overlayPackageName, userId);
701 final @OverlayInfo.State int newState = calculateNewState(targetPackage, overlayPackage,
702 userId, flags);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100703 if (currentState != newState) {
704 if (DEBUG) {
705 Slog.d(TAG, String.format("%s:%d: %s -> %s",
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100706 overlayPackageName, userId,
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100707 OverlayInfo.stateToString(currentState),
708 OverlayInfo.stateToString(newState)));
709 }
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100710 modified |= mSettings.setState(overlayPackageName, userId, newState);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100711 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700712 return modified;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100713 }
714
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100715 private @OverlayInfo.State int calculateNewState(@Nullable final PackageInfo targetPackage,
716 @Nullable final PackageInfo overlayPackage, final int userId, final int flags)
Mårten Kongstad38988342018-12-04 10:28:01 +0100717 throws OverlayManagerSettings.BadKeyException {
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100718
Mårten Kongstad15a0ac02019-03-26 10:30:08 +0100719 if ((flags & FLAG_TARGET_IS_BEING_REPLACED) != 0) {
720 return STATE_TARGET_IS_BEING_REPLACED;
721 }
722
723 if ((flags & FLAG_OVERLAY_IS_BEING_REPLACED) != 0) {
724 return STATE_OVERLAY_IS_BEING_REPLACED;
Mårten Kongstaddb0e34e2018-01-10 12:05:26 +0100725 }
726
727 // assert expectation on overlay package: can only be null if the flags are used
728 if (DEBUG && overlayPackage == null) {
729 throw new IllegalArgumentException("null overlay package not compatible with no flags");
730 }
731
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100732 if (targetPackage == null) {
733 return STATE_MISSING_TARGET;
734 }
735
736 if (!mIdmapManager.idmapExists(overlayPackage, userId)) {
737 return STATE_NO_IDMAP;
738 }
739
Mårten Kongstada525e222018-04-10 16:57:33 +0200740 if (overlayPackage.isStaticOverlayPackage()) {
741 return STATE_ENABLED_STATIC;
742 }
743
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100744 final boolean enabled = mSettings.getEnabled(overlayPackage.packageName, userId);
745 return enabled ? STATE_ENABLED : STATE_DISABLED;
746 }
747
748 private void removeIdmapIfPossible(@NonNull final OverlayInfo oi) {
749 // For a given package, all Android users share the same idmap file.
750 // This works because Android currently does not support users to
751 // install different versions of the same package. It also means we
752 // cannot remove an idmap file if any user still needs it.
753 //
754 // When/if the Android framework allows different versions of the same
755 // package to be installed for different users, idmap file handling
756 // should be revised:
757 //
758 // - an idmap file should be unique for each {user, package} pair
759 //
760 // - the path to the idmap file should be passed to the native Asset
761 // Manager layers, just like the path to the apk is passed today
762 //
763 // As part of that change, calls to this method should be replaced by
764 // direct calls to IdmapManager.removeIdmap, without looping over all
765 // users.
766
767 if (!mIdmapManager.idmapExists(oi)) {
768 return;
769 }
Adam Lesinskic745f422017-04-05 16:31:30 -0700770 final int[] userIds = mSettings.getUsers();
771 for (int userId : userIds) {
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100772 try {
773 final OverlayInfo tmp = mSettings.getOverlayInfo(oi.packageName, userId);
774 if (tmp != null && tmp.isEnabled()) {
775 // someone is still using the idmap file -> we cannot remove it
776 return;
777 }
778 } catch (OverlayManagerSettings.BadKeyException e) {
779 // intentionally left empty
780 }
781 }
782 mIdmapManager.removeIdmap(oi, oi.userId);
783 }
784
Adam Lesinskic745f422017-04-05 16:31:30 -0700785 interface OverlayChangeListener {
Ryan Mitchelld41d0db2018-05-09 09:01:12 -0700786
787 /**
788 * An event triggered by changes made to overlay state or settings as well as changes that
789 * add or remove target packages of overlays.
790 **/
Mårten Kongstad497945c2018-04-27 09:56:13 +0200791 void onOverlaysChanged(@NonNull String targetPackage, int userId);
Adam Lesinskic745f422017-04-05 16:31:30 -0700792 }
793
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100794 interface PackageManagerHelper {
795 PackageInfo getPackageInfo(@NonNull String packageName, int userId);
796 boolean signaturesMatching(@NonNull String packageName1, @NonNull String packageName2,
797 int userId);
798 List<PackageInfo> getOverlayPackages(int userId);
799 }
800}