Merge "Revert "OMS: add transactional API""

This commit is contained in:
Treehugger Robot
2021-01-13 00:00:42 +00:00
committed by Gerrit Code Review
5 changed files with 167 additions and 568 deletions

View File

@@ -17,7 +17,6 @@
package android.content.om;
import android.content.om.OverlayInfo;
import android.content.om.OverlayManagerTransaction;
/**
* Api for getting information about overlay packages.
@@ -164,18 +163,4 @@ interface IOverlayManager {
* @param packageName The name of the overlay package whose idmap should be deleted.
*/
void invalidateCachesForOverlay(in String packageName, in int userIs);
/**
* Perform a series of requests related to overlay packages. This is an
* atomic operation: either all requests were performed successfully and
* the changes were propagated to the rest of the system, or at least one
* request could not be performed successfully and nothing is changed and
* nothing is propagated to the rest of the system.
*
* @see OverlayManagerTransaction
*
* @param transaction the series of overlay related requests to perform
* @throws SecurityException if the transaction failed
*/
void commit(in OverlayManagerTransaction transaction);
}

View File

@@ -253,29 +253,6 @@ public class OverlayManager {
}
}
/**
* Perform a series of requests related to overlay packages. This is an
* atomic operation: either all requests were performed successfully and
* the changes were propagated to the rest of the system, or at least one
* request could not be performed successfully and nothing is changed and
* nothing is propagated to the rest of the system.
*
* @see OverlayManagerTransaction
*
* @param transaction the series of overlay related requests to perform
* @throws Exception if not all the requests could be successfully and
* atomically executed
*
* @hide
*/
public void commit(@NonNull final OverlayManagerTransaction transaction) {
try {
mService.commit(transaction);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Starting on R, actor enforcement and app visibility changes introduce additional failure
* cases, but the SecurityException thrown with these checks is unexpected for existing

View File

@@ -1,19 +0,0 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.content.om;
parcelable OverlayManagerTransaction;

View File

@@ -1,216 +0,0 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.content.om;
import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Container for a batch of requests to the OverlayManagerService.
*
* Transactions are created using a builder interface. Example usage:
*
* final OverlayManager om = ctx.getSystemService(OverlayManager.class);
* final OverlayManagerTransaction t = new OverlayManagerTransaction.Builder()
* .setEnabled(...)
* .setEnabled(...)
* .build();
* om.commit(t);
*
* @hide
*/
public class OverlayManagerTransaction
implements Iterable<OverlayManagerTransaction.Request>, Parcelable {
// TODO: remove @hide from this class when OverlayManager is added to the
// SDK, but keep OverlayManagerTransaction.Request @hidden
private final List<Request> mRequests;
OverlayManagerTransaction(@NonNull final List<Request> requests) {
checkNotNull(requests);
if (requests.contains(null)) {
throw new IllegalArgumentException("null request");
}
mRequests = requests;
}
private OverlayManagerTransaction(@NonNull final Parcel source) {
final int size = source.readInt();
mRequests = new ArrayList<Request>(size);
for (int i = 0; i < size; i++) {
final int request = source.readInt();
final String packageName = source.readString();
final int userId = source.readInt();
mRequests.add(new Request(request, packageName, userId));
}
}
@Override
public Iterator<Request> iterator() {
return mRequests.iterator();
}
@Override
public String toString() {
return String.format("OverlayManagerTransaction { mRequests = %s }", mRequests);
}
/**
* A single unit of the transaction, such as a request to enable an
* overlay, or to disable an overlay.
*
* @hide
*/
public static class Request {
@IntDef(prefix = "TYPE_", value = {
TYPE_SET_ENABLED,
TYPE_SET_DISABLED,
})
@Retention(RetentionPolicy.SOURCE)
@interface RequestType {}
public static final int TYPE_SET_ENABLED = 0;
public static final int TYPE_SET_DISABLED = 1;
@RequestType public final int type;
public final String packageName;
public final int userId;
public Request(@RequestType final int type, @NonNull final String packageName,
final int userId) {
this.type = type;
this.packageName = packageName;
this.userId = userId;
}
@Override
public String toString() {
return String.format("Request{type=0x%02x (%s), packageName=%s, userId=%d}",
type, typeToString(), packageName, userId);
}
/**
* Translate the request type into a human readable string. Only
* intended for debugging.
*
* @hide
*/
public String typeToString() {
switch (type) {
case TYPE_SET_ENABLED: return "TYPE_SET_ENABLED";
case TYPE_SET_DISABLED: return "TYPE_SET_DISABLED";
default: return String.format("TYPE_UNKNOWN (0x%02x)", type);
}
}
}
/**
* Builder class for OverlayManagerTransaction objects.
*
* @hide
*/
public static class Builder {
private final List<Request> mRequests = new ArrayList<>();
/**
* Request that an overlay package be enabled and change its loading
* order to the last package to be loaded, or disabled
*
* If the caller has the correct permissions, it is always possible to
* disable an overlay. Due to technical and security reasons it may not
* always be possible to enable an overlay, for instance if the overlay
* does not successfully overlay any target resources due to
* overlayable policy restrictions.
*
* An enabled overlay is a part of target package's resources, i.e. it will
* be part of any lookups performed via {@link android.content.res.Resources}
* and {@link android.content.res.AssetManager}. A disabled overlay will no
* longer affect the resources of the target package. If the target is
* currently running, its outdated resources will be replaced by new ones.
*
* @param packageName The name of the overlay package.
* @param enable true to enable the overlay, false to disable it.
* @return this Builder object, so you can chain additional requests
*/
public Builder setEnabled(@NonNull String packageName, boolean enable) {
return setEnabled(packageName, enable, UserHandle.myUserId());
}
/**
* @hide
*/
public Builder setEnabled(@NonNull String packageName, boolean enable, int userId) {
checkNotNull(packageName);
@Request.RequestType final int type =
enable ? Request.TYPE_SET_ENABLED : Request.TYPE_SET_DISABLED;
mRequests.add(new Request(type, packageName, userId));
return this;
}
/**
* Create a new transaction out of the requests added so far. Execute
* the transaction by calling OverlayManager#commit.
*
* @see OverlayManager#commit
* @return a new transaction
*/
public OverlayManagerTransaction build() {
return new OverlayManagerTransaction(mRequests);
}
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
final int size = mRequests.size();
dest.writeInt(size);
for (int i = 0; i < size; i++) {
final Request req = mRequests.get(i);
dest.writeInt(req.type);
dest.writeString(req.packageName);
dest.writeInt(req.userId);
}
}
public static final Parcelable.Creator<OverlayManagerTransaction> CREATOR =
new Parcelable.Creator<OverlayManagerTransaction>() {
@Override
public OverlayManagerTransaction createFromParcel(Parcel source) {
return new OverlayManagerTransaction(source);
}
@Override
public OverlayManagerTransaction[] newArray(int size) {
return new OverlayManagerTransaction[size];
}
};
}

View File

@@ -24,8 +24,6 @@ import static android.content.Intent.ACTION_PACKAGE_REMOVED;
import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.EXTRA_REASON;
import static android.content.om.OverlayManagerTransaction.Request.TYPE_SET_DISABLED;
import static android.content.om.OverlayManagerTransaction.Request.TYPE_SET_ENABLED;
import static android.content.pm.PackageManager.SIGNATURE_MATCH;
import static android.os.Trace.TRACE_TAG_RRO;
import static android.os.Trace.traceBegin;
@@ -43,7 +41,6 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.om.IOverlayManager;
import android.content.om.OverlayInfo;
import android.content.om.OverlayManagerTransaction;
import android.content.om.OverlayableInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
@@ -87,14 +84,11 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
/**
@@ -244,13 +238,8 @@ public final class OverlayManagerService extends SystemService {
private final OverlayActorEnforcer mActorEnforcer;
private final Consumer<PackageAndUser> mPropagateOverlayChange = (pair) -> {
persistSettings();
FgThread.getHandler().post(() -> {
List<String> affectedTargets = updatePackageManager(pair.packageName, pair.userId);
updateActivityManager(affectedTargets, pair.userId);
broadcastActionOverlayChanged(affectedTargets, pair.userId);
});
private final Consumer<PackageAndUser> mOnOverlaysChanged = (pair) -> {
onOverlaysChanged(pair.packageName, pair.userId);
};
public OverlayManagerService(@NonNull final Context context) {
@@ -309,11 +298,11 @@ public final class OverlayManagerService extends SystemService {
for (int i = 0; i < userCount; i++) {
final UserInfo userInfo = users.get(i);
if (!userInfo.supportsSwitchTo() && userInfo.id != UserHandle.USER_SYSTEM) {
// Initialize any users that can't be switched to, as their state would
// Initialize any users that can't be switched to, as there state would
// never be setup in onSwitchUser(). We will switch to the system user right
// after this, and its state will be setup there.
final List<String> targets = mImpl.updateOverlaysForUser(users.get(i).id);
updatePackageManager(targets, users.get(i).id);
updateOverlayPaths(users.get(i).id, targets);
}
}
}
@@ -327,8 +316,7 @@ public final class OverlayManagerService extends SystemService {
// any asset changes to the rest of the system
synchronized (mLock) {
final List<String> targets = mImpl.updateOverlaysForUser(newUserId);
final List<String> affectedTargets = updatePackageManager(targets, newUserId);
updateActivityManager(affectedTargets, newUserId);
updateAssets(newUserId, targets);
}
persistSettings();
} finally {
@@ -418,10 +406,10 @@ public final class OverlayManagerService extends SystemService {
try {
if (pi.isOverlayPackage()) {
mImpl.onOverlayPackageAdded(packageName, userId)
.ifPresent(mPropagateOverlayChange);
.ifPresent(mOnOverlaysChanged);
} else {
mImpl.onTargetPackageAdded(packageName, userId)
.ifPresent(mPropagateOverlayChange);
.ifPresent(mOnOverlaysChanged);
}
} catch (OperationFailedException e) {
Slog.e(TAG, "onPackageAdded internal error", e);
@@ -448,10 +436,10 @@ public final class OverlayManagerService extends SystemService {
try {
if (pi.isOverlayPackage()) {
mImpl.onOverlayPackageChanged(packageName, userId)
.ifPresent(mPropagateOverlayChange);
.ifPresent(mOnOverlaysChanged);
} else {
mImpl.onTargetPackageChanged(packageName, userId)
.ifPresent(mPropagateOverlayChange);
.ifPresent(mOnOverlaysChanged);
}
} catch (OperationFailedException e) {
Slog.e(TAG, "onPackageChanged internal error", e);
@@ -475,7 +463,7 @@ public final class OverlayManagerService extends SystemService {
if (oi != null) {
try {
mImpl.onOverlayPackageReplacing(packageName, userId)
.ifPresent(mPropagateOverlayChange);
.ifPresent(mOnOverlaysChanged);
} catch (OperationFailedException e) {
Slog.e(TAG, "onPackageReplacing internal error", e);
}
@@ -500,10 +488,10 @@ public final class OverlayManagerService extends SystemService {
try {
if (pi.isOverlayPackage()) {
mImpl.onOverlayPackageReplaced(packageName, userId)
.ifPresent(mPropagateOverlayChange);
.ifPresent(mOnOverlaysChanged);
} else {
mImpl.onTargetPackageReplaced(packageName, userId)
.ifPresent(mPropagateOverlayChange);
.ifPresent(mOnOverlaysChanged);
}
} catch (OperationFailedException e) {
Slog.e(TAG, "onPackageReplaced internal error", e);
@@ -528,10 +516,10 @@ public final class OverlayManagerService extends SystemService {
try {
if (oi != null) {
mImpl.onOverlayPackageRemoved(packageName, userId)
.ifPresent(mPropagateOverlayChange);
.ifPresent(mOnOverlaysChanged);
} else {
mImpl.onTargetPackageRemoved(packageName, userId)
.ifPresent(mPropagateOverlayChange);
.ifPresent(mOnOverlaysChanged);
}
} catch (OperationFailedException e) {
Slog.e(TAG, "onPackageRemoved internal error", e);
@@ -557,7 +545,7 @@ public final class OverlayManagerService extends SystemService {
synchronized (mLock) {
targets = mImpl.updateOverlaysForUser(userId);
}
updatePackageManager(targets, userId);
updateOverlayPaths(userId, targets);
} finally {
traceEnd(TRACE_TAG_RRO);
}
@@ -654,7 +642,7 @@ public final class OverlayManagerService extends SystemService {
synchronized (mLock) {
try {
mImpl.setEnabled(packageName, enable, realUserId)
.ifPresent(mPropagateOverlayChange);
.ifPresent(mOnOverlaysChanged);
return true;
} catch (OperationFailedException e) {
return false;
@@ -686,7 +674,7 @@ public final class OverlayManagerService extends SystemService {
try {
mImpl.setEnabledExclusive(packageName,
false /* withinCategory */, realUserId)
.ifPresent(mPropagateOverlayChange);
.ifPresent(mOnOverlaysChanged);
return true;
} catch (OperationFailedException e) {
return false;
@@ -719,7 +707,7 @@ public final class OverlayManagerService extends SystemService {
try {
mImpl.setEnabledExclusive(packageName,
true /* withinCategory */, realUserId)
.ifPresent(mPropagateOverlayChange);
.ifPresent(mOnOverlaysChanged);
return true;
} catch (OperationFailedException e) {
return false;
@@ -751,7 +739,7 @@ public final class OverlayManagerService extends SystemService {
synchronized (mLock) {
try {
mImpl.setPriority(packageName, parentPackageName, realUserId)
.ifPresent(mPropagateOverlayChange);
.ifPresent(mOnOverlaysChanged);
return true;
} catch (OperationFailedException e) {
return false;
@@ -781,7 +769,7 @@ public final class OverlayManagerService extends SystemService {
synchronized (mLock) {
try {
mImpl.setHighestPriority(packageName, realUserId)
.ifPresent(mPropagateOverlayChange);
.ifPresent(mOnOverlaysChanged);
return true;
} catch (OperationFailedException e) {
return false;
@@ -811,7 +799,7 @@ public final class OverlayManagerService extends SystemService {
synchronized (mLock) {
try {
mImpl.setLowestPriority(packageName, realUserId)
.ifPresent(mPropagateOverlayChange);
.ifPresent(mOnOverlaysChanged);
return true;
} catch (OperationFailedException e) {
return false;
@@ -863,120 +851,6 @@ public final class OverlayManagerService extends SystemService {
}
}
@Override
public void commit(@NonNull final OverlayManagerTransaction transaction)
throws RemoteException {
try {
traceBegin(TRACE_TAG_RRO, "OMS#commit " + transaction);
try {
executeAllRequests(transaction);
} catch (Exception e) {
final long ident = Binder.clearCallingIdentity();
try {
restoreSettings();
} finally {
Binder.restoreCallingIdentity(ident);
}
Slog.d(TAG, "commit failed: " + e.getMessage(), e);
throw new SecurityException("commit failed"
+ (DEBUG ? ": " + e.getMessage() : ""));
}
} finally {
traceEnd(TRACE_TAG_RRO);
}
}
private Optional<PackageAndUser> executeRequest(
@NonNull final OverlayManagerTransaction.Request request) throws Exception {
final int realUserId = handleIncomingUser(request.userId, request.typeToString());
enforceActor(request.packageName, request.typeToString(), realUserId);
final long ident = Binder.clearCallingIdentity();
try {
switch (request.type) {
case TYPE_SET_ENABLED:
Optional<PackageAndUser> opt1 =
mImpl.setEnabled(request.packageName, true, request.userId);
Optional<PackageAndUser> opt2 =
mImpl.setHighestPriority(request.packageName, request.userId);
// Both setEnabled and setHighestPriority affected the same
// target package and user: if both return non-empty
// Optionals, they are identical
return opt1.isPresent() ? opt1 : opt2;
case TYPE_SET_DISABLED:
return mImpl.setEnabled(request.packageName, false, request.userId);
default:
throw new IllegalArgumentException("unsupported request: " + request);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private void executeAllRequests(@NonNull final OverlayManagerTransaction transaction)
throws Exception {
if (DEBUG) {
Slog.d(TAG, "commit " + transaction);
}
if (transaction == null) {
throw new IllegalArgumentException("null transaction");
}
// map: userId -> list<targetPackageName>
SparseArray<List<String>> affectedTargetsToUpdate = new SparseArray<>();
synchronized (mLock) {
// map: userId -> set<targetPackageName>
SparseArray<Set<String>> targetsToUpdate = new SparseArray<>();
// execute the requests (as calling user)
for (final OverlayManagerTransaction.Request request : transaction) {
executeRequest(request).ifPresent(target -> {
Set<String> userTargets = targetsToUpdate.get(target.userId);
if (userTargets == null) {
userTargets = new ArraySet<String>();
targetsToUpdate.put(target.userId, userTargets);
}
userTargets.add(target.packageName);
});
}
// past the point of no return: the entire transaction has been
// processed successfully, we can no longer fail: continue as
// system_server
final long ident = Binder.clearCallingIdentity();
try {
persistSettings();
// inform the package manager about the new paths
for (int index = 0; index < targetsToUpdate.size(); index++) {
final int userId = targetsToUpdate.keyAt(index);
final List<String> affectedTargets =
updatePackageManager(targetsToUpdate.valueAt(index), userId);
affectedTargetsToUpdate.put(userId, affectedTargets);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
} // synchronized (mLock)
FgThread.getHandler().post(() -> {
final long ident = Binder.clearCallingIdentity();
try {
// schedule apps to refresh + broadcast the ACTION_OVERLAY_CHANGED intents
for (int index = 0; index < affectedTargetsToUpdate.size(); index++) {
final int userId = affectedTargetsToUpdate.keyAt(index);
final List<String> packageNames = affectedTargetsToUpdate.valueAt(index);
updateActivityManager(packageNames, userId);
broadcastActionOverlayChanged(packageNames, userId);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
});
}
@Override
public void onShellCommand(@NonNull final FileDescriptor in,
@NonNull final FileDescriptor out, @NonNull final FileDescriptor err,
@@ -1098,7 +972,152 @@ public final class OverlayManagerService extends SystemService {
}
};
private static final class PackageManagerHelperImpl implements PackageManagerHelper {
private void onOverlaysChanged(@NonNull final String targetPackageName, final int userId) {
persistSettings();
FgThread.getHandler().post(() -> {
updateAssets(userId, targetPackageName);
final Intent intent = new Intent(ACTION_OVERLAY_CHANGED,
Uri.fromParts("package", targetPackageName, null));
intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
if (DEBUG) {
Slog.d(TAG, "send broadcast " + intent);
}
try {
ActivityManager.getService().broadcastIntent(null, intent, null, null, 0,
null, null, null, android.app.AppOpsManager.OP_NONE, null, false, false,
userId);
} catch (RemoteException e) {
// Intentionally left empty.
}
});
}
/**
* Updates the target packages' set of enabled overlays in PackageManager.
*/
private ArrayList<String> updateOverlayPaths(int userId, List<String> targetPackageNames) {
try {
traceBegin(TRACE_TAG_RRO, "OMS#updateOverlayPaths " + targetPackageNames);
if (DEBUG) {
Slog.d(TAG, "Updating overlay assets");
}
final PackageManagerInternal pm =
LocalServices.getService(PackageManagerInternal.class);
final boolean updateFrameworkRes = targetPackageNames.contains("android");
if (updateFrameworkRes) {
targetPackageNames = pm.getTargetPackageNames(userId);
}
final Map<String, List<String>> pendingChanges =
new ArrayMap<>(targetPackageNames.size());
synchronized (mLock) {
final List<String> frameworkOverlays =
mImpl.getEnabledOverlayPackageNames("android", userId);
final int n = targetPackageNames.size();
for (int i = 0; i < n; i++) {
final String targetPackageName = targetPackageNames.get(i);
List<String> list = new ArrayList<>();
if (!"android".equals(targetPackageName)) {
list.addAll(frameworkOverlays);
}
list.addAll(mImpl.getEnabledOverlayPackageNames(targetPackageName, userId));
pendingChanges.put(targetPackageName, list);
}
}
final HashSet<String> updatedPackages = new HashSet<>();
final int n = targetPackageNames.size();
for (int i = 0; i < n; i++) {
final String targetPackageName = targetPackageNames.get(i);
if (DEBUG) {
Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=["
+ TextUtils.join(",", pendingChanges.get(targetPackageName))
+ "] userId=" + userId);
}
if (!pm.setEnabledOverlayPackages(
userId, targetPackageName, pendingChanges.get(targetPackageName),
updatedPackages)) {
Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
targetPackageName, userId));
}
}
return new ArrayList<>(updatedPackages);
} finally {
traceEnd(TRACE_TAG_RRO);
}
}
private void updateAssets(final int userId, final String targetPackageName) {
updateAssets(userId, Collections.singletonList(targetPackageName));
}
private void updateAssets(final int userId, List<String> targetPackageNames) {
final IActivityManager am = ActivityManager.getService();
try {
final ArrayList<String> updatedPaths = updateOverlayPaths(userId, targetPackageNames);
am.scheduleApplicationInfoChanged(updatedPaths, userId);
} catch (RemoteException e) {
// Intentionally left empty.
}
}
private void persistSettings() {
if (DEBUG) {
Slog.d(TAG, "Writing overlay settings");
}
synchronized (mLock) {
FileOutputStream stream = null;
try {
stream = mSettingsFile.startWrite();
mSettings.persist(stream);
mSettingsFile.finishWrite(stream);
} catch (IOException | XmlPullParserException e) {
mSettingsFile.failWrite(stream);
Slog.e(TAG, "failed to persist overlay state", e);
}
}
}
private void restoreSettings() {
try {
traceBegin(TRACE_TAG_RRO, "OMS#restoreSettings");
synchronized (mLock) {
if (!mSettingsFile.getBaseFile().exists()) {
return;
}
try (FileInputStream stream = mSettingsFile.openRead()) {
mSettings.restore(stream);
// We might have data for dying users if the device was
// restarted before we received USER_REMOVED. Remove data for
// users that will not exist after the system is ready.
final List<UserInfo> liveUsers = mUserManager.getUsers(true /*excludeDying*/);
final int[] liveUserIds = new int[liveUsers.size()];
for (int i = 0; i < liveUsers.size(); i++) {
liveUserIds[i] = liveUsers.get(i).getUserHandle().getIdentifier();
}
Arrays.sort(liveUserIds);
for (int userId : mSettings.getUsers()) {
if (Arrays.binarySearch(liveUserIds, userId) < 0) {
mSettings.removeUser(userId);
}
}
} catch (IOException | XmlPullParserException e) {
Slog.e(TAG, "failed to restore overlay state", e);
}
}
} finally {
traceEnd(TRACE_TAG_RRO);
}
}
private static final class PackageManagerHelperImpl implements PackageManagerHelper {
private final Context mContext;
private final IPackageManager mPackageManager;
@@ -1308,151 +1327,4 @@ public final class OverlayManagerService extends SystemService {
}
}
}
// Helper methods to update other parts of the system or read/write
// settings: these methods should never call into each other!
private void broadcastActionOverlayChanged(@NonNull final Collection<String> packageNames,
final int userId) {
for (final String packageName : packageNames) {
broadcastActionOverlayChanged(packageName, userId);
}
}
private void broadcastActionOverlayChanged(@NonNull final String targetPackageName,
final int userId) {
final Intent intent = new Intent(ACTION_OVERLAY_CHANGED,
Uri.fromParts("package", targetPackageName, null));
intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
try {
ActivityManager.getService().broadcastIntent(null, intent, null, null, 0, null, null,
null, android.app.AppOpsManager.OP_NONE, null, false, false, userId);
} catch (RemoteException e) {
// Intentionally left empty.
}
}
/**
* Tell the activity manager to tell a set of packages to reload their
* resources.
*/
private void updateActivityManager(List<String> targetPackageNames, final int userId) {
final IActivityManager am = ActivityManager.getService();
try {
am.scheduleApplicationInfoChanged(targetPackageNames, userId);
} catch (RemoteException e) {
// Intentionally left empty.
}
}
private ArrayList<String> updatePackageManager(String targetPackageNames, final int userId) {
return updatePackageManager(Collections.singletonList(targetPackageNames), userId);
}
/**
* Updates the target packages' set of enabled overlays in PackageManager.
* @return the package names of affected targets (a superset of
* targetPackageNames: the target themserlves and shared libraries)
*/
private ArrayList<String> updatePackageManager(@NonNull Collection<String> targetPackageNames,
final int userId) {
try {
traceBegin(TRACE_TAG_RRO, "OMS#updatePackageManager " + targetPackageNames);
if (DEBUG) {
Slog.d(TAG, "Update package manager about changed overlays");
}
final PackageManagerInternal pm =
LocalServices.getService(PackageManagerInternal.class);
final boolean updateFrameworkRes = targetPackageNames.contains("android");
if (updateFrameworkRes) {
targetPackageNames = pm.getTargetPackageNames(userId);
}
final Map<String, List<String>> pendingChanges =
new ArrayMap<>(targetPackageNames.size());
synchronized (mLock) {
final List<String> frameworkOverlays =
mImpl.getEnabledOverlayPackageNames("android", userId);
for (final String targetPackageName : targetPackageNames) {
List<String> list = new ArrayList<>();
if (!"android".equals(targetPackageName)) {
list.addAll(frameworkOverlays);
}
list.addAll(mImpl.getEnabledOverlayPackageNames(targetPackageName, userId));
pendingChanges.put(targetPackageName, list);
}
}
final HashSet<String> updatedPackages = new HashSet<>();
for (final String targetPackageName : targetPackageNames) {
if (DEBUG) {
Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=["
+ TextUtils.join(",", pendingChanges.get(targetPackageName))
+ "] userId=" + userId);
}
if (!pm.setEnabledOverlayPackages(
userId, targetPackageName, pendingChanges.get(targetPackageName),
updatedPackages)) {
Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
targetPackageName, userId));
}
}
return new ArrayList<>(updatedPackages);
} finally {
traceEnd(TRACE_TAG_RRO);
}
}
private void persistSettings() {
if (DEBUG) {
Slog.d(TAG, "Writing overlay settings");
}
synchronized (mLock) {
FileOutputStream stream = null;
try {
stream = mSettingsFile.startWrite();
mSettings.persist(stream);
mSettingsFile.finishWrite(stream);
} catch (IOException | XmlPullParserException e) {
mSettingsFile.failWrite(stream);
Slog.e(TAG, "failed to persist overlay state", e);
}
}
}
private void restoreSettings() {
try {
traceBegin(TRACE_TAG_RRO, "OMS#restoreSettings");
synchronized (mLock) {
if (!mSettingsFile.getBaseFile().exists()) {
return;
}
try (FileInputStream stream = mSettingsFile.openRead()) {
mSettings.restore(stream);
// We might have data for dying users if the device was
// restarted before we received USER_REMOVED. Remove data for
// users that will not exist after the system is ready.
final List<UserInfo> liveUsers = mUserManager.getUsers(true /*excludeDying*/);
final int[] liveUserIds = new int[liveUsers.size()];
for (int i = 0; i < liveUsers.size(); i++) {
liveUserIds[i] = liveUsers.get(i).getUserHandle().getIdentifier();
}
Arrays.sort(liveUserIds);
for (int userId : mSettings.getUsers()) {
if (Arrays.binarySearch(liveUserIds, userId) < 0) {
mSettings.removeUser(userId);
}
}
} catch (IOException | XmlPullParserException e) {
Slog.e(TAG, "failed to restore overlay state", e);
}
}
} finally {
traceEnd(TRACE_TAG_RRO);
}
}
}