OMS: Update PM on main thread with lock

Updating package manager was happening on a handler thread without
obtaining the OMS lock. Rather than lock in the handler thread,
move the communication with PMS to the main thread.

Bug: 180522470
Test: atest OverlayDeviceTests
Change-Id: Id06fc7294cee9db40d34b26807b577ff2b609c37
This commit is contained in:
Ryan Mitchell
2021-02-16 12:50:51 -08:00
parent d145f376ca
commit 95323fb4bf

View File

@@ -103,7 +103,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
/**
@@ -312,7 +311,7 @@ public final class OverlayManagerService extends SystemService {
// Initialize any users that can't be switched to, as their state would
// never be setup in onSwitchUser(). We will switch to the system user right
// after this, and its state will be setup there.
updatePackageManager(mImpl.updateOverlaysForUser(users.get(i).id));
updatePackageManagerLocked(mImpl.updateOverlaysForUser(users.get(i).id));
}
}
}
@@ -329,9 +328,8 @@ public final class OverlayManagerService extends SystemService {
// ensure overlays in the settings are up-to-date, and propagate
// any asset changes to the rest of the system
synchronized (mLock) {
updateActivityManager(updatePackageManager(mImpl.updateOverlaysForUser(newUserId)));
updateTargetPackagesLocked(mImpl.updateOverlaysForUser(newUserId));
}
persistSettings();
} finally {
traceEnd(TRACE_TAG_RRO);
}
@@ -415,7 +413,8 @@ public final class OverlayManagerService extends SystemService {
packageName, userId);
if (pkg != null && !mPackageManager.isInstantApp(packageName, userId)) {
try {
updateTargetPackages(mImpl.onPackageAdded(packageName, userId));
updateTargetPackagesLocked(
mImpl.onPackageAdded(packageName, userId));
} catch (OperationFailedException e) {
Slog.e(TAG, "onPackageAdded internal error", e);
}
@@ -437,7 +436,8 @@ public final class OverlayManagerService extends SystemService {
packageName, userId);
if (pkg != null && !mPackageManager.isInstantApp(packageName, userId)) {
try {
updateTargetPackages(mImpl.onPackageChanged(packageName, userId));
updateTargetPackagesLocked(
mImpl.onPackageChanged(packageName, userId));
} catch (OperationFailedException e) {
Slog.e(TAG, "onPackageChanged internal error", e);
}
@@ -459,7 +459,8 @@ public final class OverlayManagerService extends SystemService {
packageName, userId);
if (pkg != null && !mPackageManager.isInstantApp(packageName, userId)) {
try {
updateTargetPackages(mImpl.onPackageReplacing(packageName, userId));
updateTargetPackagesLocked(
mImpl.onPackageReplacing(packageName, userId));
} catch (OperationFailedException e) {
Slog.e(TAG, "onPackageReplacing internal error", e);
}
@@ -481,7 +482,8 @@ public final class OverlayManagerService extends SystemService {
packageName, userId);
if (pkg != null && !mPackageManager.isInstantApp(packageName, userId)) {
try {
updateTargetPackages(mImpl.onPackageReplaced(packageName, userId));
updateTargetPackagesLocked(
mImpl.onPackageReplaced(packageName, userId));
} catch (OperationFailedException e) {
Slog.e(TAG, "onPackageReplaced internal error", e);
}
@@ -500,7 +502,7 @@ public final class OverlayManagerService extends SystemService {
for (int userId : userIds) {
synchronized (mLock) {
mPackageManager.onPackageRemoved(packageName, userId);
updateTargetPackages(mImpl.onPackageRemoved(packageName, userId));
updateTargetPackagesLocked(mImpl.onPackageRemoved(packageName, userId));
}
}
} finally {
@@ -519,7 +521,7 @@ public final class OverlayManagerService extends SystemService {
try {
traceBegin(TRACE_TAG_RRO, "OMS ACTION_USER_ADDED");
synchronized (mLock) {
updatePackageManager(mImpl.updateOverlaysForUser(userId));
updatePackageManagerLocked(mImpl.updateOverlaysForUser(userId));
}
} finally {
traceEnd(TRACE_TAG_RRO);
@@ -624,7 +626,8 @@ public final class OverlayManagerService extends SystemService {
try {
synchronized (mLock) {
try {
updateTargetPackages(mImpl.setEnabled(overlay, enable, realUserId));
updateTargetPackagesLocked(
mImpl.setEnabled(overlay, enable, realUserId));
return true;
} catch (OperationFailedException e) {
return false;
@@ -656,9 +659,10 @@ public final class OverlayManagerService extends SystemService {
try {
synchronized (mLock) {
try {
mImpl.setEnabledExclusive(overlay,
false /* withinCategory */, realUserId)
.ifPresent(OverlayManagerService.this::updateTargetPackages);
mImpl.setEnabledExclusive(
overlay, false /* withinCategory */, realUserId)
.ifPresent(
OverlayManagerService.this::updateTargetPackagesLocked);
return true;
} catch (OperationFailedException e) {
return false;
@@ -693,7 +697,7 @@ public final class OverlayManagerService extends SystemService {
try {
mImpl.setEnabledExclusive(overlay,
true /* withinCategory */, realUserId)
.ifPresent(OverlayManagerService.this::updateTargetPackages);
.ifPresent(OverlayManagerService.this::updateTargetPackagesLocked);
return true;
} catch (OperationFailedException e) {
return false;
@@ -728,7 +732,7 @@ public final class OverlayManagerService extends SystemService {
synchronized (mLock) {
try {
mImpl.setPriority(overlay, parentOverlay, realUserId)
.ifPresent(OverlayManagerService.this::updateTargetPackages);
.ifPresent(OverlayManagerService.this::updateTargetPackagesLocked);
return true;
} catch (OperationFailedException e) {
return false;
@@ -759,7 +763,8 @@ public final class OverlayManagerService extends SystemService {
try {
synchronized (mLock) {
try {
updateTargetPackages(mImpl.setHighestPriority(overlay, realUserId));
updateTargetPackagesLocked(
mImpl.setHighestPriority(overlay, realUserId));
return true;
} catch (OperationFailedException e) {
return false;
@@ -791,7 +796,7 @@ public final class OverlayManagerService extends SystemService {
synchronized (mLock) {
try {
mImpl.setLowestPriority(overlay, realUserId)
.ifPresent(OverlayManagerService.this::updateTargetPackages);
.ifPresent(OverlayManagerService.this::updateTargetPackagesLocked);
return true;
} catch (OperationFailedException e) {
return false;
@@ -945,27 +950,12 @@ public final class OverlayManagerService extends SystemService {
throw new IllegalArgumentException("null transaction");
}
// map: userId -> set<package-name>: target packages of overlays in
// this transaction
final SparseArray<Set<String>> transactionTargets = new SparseArray<>();
// map: userId -> set<package-name>: packages that need to reload
// their resources due to changes to the overlays in this
// transaction
final SparseArray<List<String>> affectedPackagesToUpdate = new SparseArray<>();
synchronized (mLock) {
// execute the requests (as calling user)
Set<PackageAndUser> affectedPackagesToUpdate = null;
for (final OverlayManagerTransaction.Request request : transaction) {
executeRequest(request).forEach(
target -> {
Set<String> userTargets = transactionTargets.get(target.userId);
if (userTargets == null) {
userTargets = new ArraySet<>();
transactionTargets.put(target.userId, userTargets);
}
userTargets.add(target.packageName);
});
affectedPackagesToUpdate = CollectionUtils.addAll(affectedPackagesToUpdate,
executeRequest(request));
}
// past the point of no return: the entire transaction has been
@@ -973,37 +963,11 @@ public final class OverlayManagerService extends SystemService {
// system_server
final long ident = Binder.clearCallingIdentity();
try {
persistSettings();
// inform the package manager about the new paths
for (int index = 0; index < transactionTargets.size(); index++) {
final int userId = transactionTargets.keyAt(index);
final List<String> affectedTargets =
updatePackageManager(transactionTargets.valueAt(index), userId);
affectedPackagesToUpdate.put(userId, affectedTargets);
}
updateTargetPackagesLocked(affectedPackagesToUpdate);
} finally {
Binder.restoreCallingIdentity(ident);
}
} // synchronized (mLock)
FgThread.getHandler().post(() -> {
final long ident = Binder.clearCallingIdentity();
try {
// schedule apps to refresh
updateActivityManager(affectedPackagesToUpdate);
// broadcast the ACTION_OVERLAY_CHANGED intents
for (int index = 0; index < transactionTargets.size(); index++) {
final int userId = transactionTargets.keyAt(index);
for (String pkg: transactionTargets.valueAt(index)) {
broadcastActionOverlayChanged(pkg, userId);
}
}
} finally {
Binder.restoreCallingIdentity(ident);
}
});
}
}
@Override
@@ -1380,32 +1344,37 @@ public final class OverlayManagerService extends SystemService {
}
}
private void updateTargetPackages(@Nullable PackageAndUser updatedTarget) {
private void updateTargetPackagesLocked(@Nullable PackageAndUser updatedTarget) {
if (updatedTarget != null) {
updateTargetPackages(Set.of(updatedTarget));
updateTargetPackagesLocked(Set.of(updatedTarget));
}
}
private void updateTargetPackages(@Nullable Set<PackageAndUser> updatedTargets) {
private void updateTargetPackagesLocked(@Nullable Set<PackageAndUser> updatedTargets) {
if (CollectionUtils.isEmpty(updatedTargets)) {
return;
}
persistSettings();
persistSettingsLocked();
final SparseArray<ArraySet<String>> userTargets = groupTargetsByUserId(updatedTargets);
FgThread.getHandler().post(() -> {
for (int i = 0, n = userTargets.size(); i < n; i++) {
final ArraySet<String> targets = userTargets.valueAt(i);
final int userId = userTargets.keyAt(i);
for (int i = 0, n = userTargets.size(); i < n; i++) {
final ArraySet<String> targets = userTargets.valueAt(i);
final int userId = userTargets.keyAt(i);
final List<String> affectedPackages = updatePackageManagerLocked(targets, userId);
if (affectedPackages.isEmpty()) {
// The package manager paths are already up-to-date.
continue;
}
// Update the overlay paths in package manager.
final List<String> affectedPackages = updatePackageManager(targets, userId);
FgThread.getHandler().post(() -> {
// Send configuration changed events for all target packages that have been affected
// by overlay state changes.
updateActivityManager(affectedPackages, userId);
// Overlays targeting shared libraries may cause more packages to need to be
// refreshed.
// Do not send broadcasts for all affected targets. Overlays targeting the framework
// or shared libraries may cause too many broadcasts to be sent at once.
broadcastActionOverlayChanged(targets, userId);
}
});
});
}
}
@Nullable
@@ -1428,20 +1397,17 @@ public final class OverlayManagerService extends SystemService {
private static void broadcastActionOverlayChanged(@NonNull final Set<String> targetPackages,
final int userId) {
CollectionUtils.forEach(targetPackages,
target -> broadcastActionOverlayChanged(target, userId));
}
private static void broadcastActionOverlayChanged(String targetPackage, final int userId) {
final Intent intent = new Intent(ACTION_OVERLAY_CHANGED,
Uri.fromParts("package", targetPackage, 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.
}
CollectionUtils.forEach(targetPackages, target -> {
final Intent intent = new Intent(ACTION_OVERLAY_CHANGED,
Uri.fromParts("package", target, 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) {
Slog.e(TAG, "broadcastActionOverlayChanged remote exception", e);
}
});
}
/**
@@ -1453,18 +1419,13 @@ public final class OverlayManagerService extends SystemService {
try {
am.scheduleApplicationInfoChanged(targetPackageNames, userId);
} catch (RemoteException e) {
// Intentionally left empty.
}
}
private void updateActivityManager(@NonNull SparseArray<List<String>> targetPackageNames) {
for (int i = 0, n = targetPackageNames.size(); i < n; i++) {
updateActivityManager(targetPackageNames.valueAt(i), targetPackageNames.keyAt(i));
Slog.e(TAG, "updateActivityManager remote exception", e);
}
}
@NonNull
private SparseArray<List<String>> updatePackageManager(@Nullable Set<PackageAndUser> targets) {
private SparseArray<List<String>> updatePackageManagerLocked(
@Nullable Set<PackageAndUser> targets) {
if (CollectionUtils.isEmpty(targets)) {
return new SparseArray<>();
}
@@ -1472,7 +1433,7 @@ public final class OverlayManagerService extends SystemService {
final SparseArray<ArraySet<String>> userTargets = groupTargetsByUserId(targets);
for (int i = 0, n = userTargets.size(); i < n; i++) {
final int userId = userTargets.keyAt(i);
affectedTargets.put(userId, updatePackageManager(userTargets.valueAt(i), userId));
affectedTargets.put(userId, updatePackageManagerLocked(userTargets.valueAt(i), userId));
}
return affectedTargets;
}
@@ -1483,10 +1444,10 @@ public final class OverlayManagerService extends SystemService {
* targetPackageNames: the target themselves and shared libraries)
*/
@NonNull
private List<String> updatePackageManager(@NonNull Collection<String> targetPackageNames,
private List<String> updatePackageManagerLocked(@NonNull Collection<String> targetPackageNames,
final int userId) {
try {
traceBegin(TRACE_TAG_RRO, "OMS#updatePackageManager " + targetPackageNames);
traceBegin(TRACE_TAG_RRO, "OMS#updatePackageManagerLocked " + targetPackageNames);
if (DEBUG) {
Slog.d(TAG, "Update package manager about changed overlays");
}
@@ -1533,20 +1494,18 @@ public final class OverlayManagerService extends SystemService {
}
}
private void persistSettings() {
private void persistSettingsLocked() {
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);
}
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);
}
}