Fix deadlock between PMS and UMS threads
Resolve circular waiting in PMS side. It holds mLock in
setEnabledSettings(), then calls
getComponentEnabledSettingInternal() -> UMS to ask mUsersLock.
To fix, move the method out of mLock block
Symptom:
PMS a: hold mSnapshotLock -> ask PMS:mLock
PMS b: hold mLock -> ask UMS:mUsersLock
UMS: hold mUsersLock -> ask PMS:mSnapshotLock
Bug: 414214527
Flag: EXEMPT bug fix
Test: atest CtsPackageInstallTestCases
Test: atest CtsPackageManagerTestCases
Test: atest CtsPackageManagerStatsHostTestCases
Change-Id: Ibad1f72477bc5b04fc1df129f593dc087272f3ee
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2035dda..444158b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -169,6 +169,7 @@
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.ExceptionUtils;
+import android.util.IntArray;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -4060,14 +4061,13 @@
// packageName -> list of components to send broadcasts now
final ArrayMap<String, ArrayList<String>> sendNowBroadcasts = new ArrayMap<>(targetSize);
- final List<PackageMetrics.ComponentStateMetrics> componentStateMetricsList =
- new ArrayList<PackageMetrics.ComponentStateMetrics>();
+ final IntArray changedComponentIndices = new IntArray();
boolean scheduleBroadcastMessage = false;
boolean isSynchronous = false;
- synchronized (mLock) {
- Computer computer = snapshotComputer();
- boolean anyChanged = false;
+ Computer computer = snapshotComputer();
+ boolean anyChanged = false;
+ synchronized (mLock) {
for (int i = 0; i < targetSize; i++) {
if (!updateAllowed[i]) {
continue;
@@ -4076,18 +4076,13 @@
final ComponentEnabledSetting setting = settings.get(i);
final String packageName = setting.getPackageName();
final PackageSetting packageSetting = pkgSettings.get(packageName);
- final PackageMetrics.ComponentStateMetrics componentStateMetrics =
- new PackageMetrics.ComponentStateMetrics(setting,
- UserHandle.getUid(userId, packageSetting.getAppId()),
- setting.isComponent() ? computer.getComponentEnabledSettingInternal(
- setting.getComponentName(), callingUid, userId)
- : packageSetting.getEnabled(userId), callingUid);
if (!setEnabledSettingInternalLocked(computer, packageSetting, setting, userId,
callingPackage)) {
continue;
}
+
anyChanged = true;
- componentStateMetricsList.add(componentStateMetrics);
+ changedComponentIndices.add(i);
if ((setting.getEnabledFlags() & PackageManager.SYNCHRONOUS) != 0) {
isSynchronous = true;
@@ -4108,7 +4103,7 @@
} else {
mPendingBroadcasts.addComponent(userId, packageName, componentName);
Trace.instant(Trace.TRACE_TAG_PACKAGE_MANAGER, "setEnabledSetting broadcast: "
- + componentName + ": " + setting.getEnabledState());
+ + componentName + ": " + setting.getEnabledState());
scheduleBroadcastMessage = true;
}
}
@@ -4140,6 +4135,27 @@
}
}
+ final List<PackageMetrics.ComponentStateMetrics> componentStateMetricsList =
+ new ArrayList<PackageMetrics.ComponentStateMetrics>();
+ final int listSize = changedComponentIndices.size();
+ for (int i = 0; i < listSize; i++) {
+ final int index = changedComponentIndices.get(i);
+ final ComponentEnabledSetting setting = settings.get(index);
+ final String packageName = setting.getPackageName();
+ final PackageStateInternal psi = computer.getPackageStateInternal(packageName);
+ // Gets component state from the old snapshot which was taken before the state change,
+ // because the metrics want to use the old state
+ final int componentOldState =
+ setting.isComponent() ? computer.getComponentEnabledSettingInternal(
+ setting.getComponentName(), callingUid, userId)
+ : psi.getUserStateOrDefault(userId).getEnabledState();
+ final PackageMetrics.ComponentStateMetrics componentStateMetrics =
+ new PackageMetrics.ComponentStateMetrics(setting,
+ UserHandle.getUid(userId, psi.getAppId()),
+ componentOldState, callingUid);
+ componentStateMetricsList.add(componentStateMetrics);
+ }
+
// Log the metrics when the component state is changed.
PackageMetrics.reportComponentStateChanged(snapshotComputer(), componentStateMetricsList,
userId);