Yell when calling installd with PM lock held.
As a matter of policy, we should never be holding the mPackages lock
while calling down into installd. This little bit of logic helps us
catch accidental cases where this happens.
Change-Id: I676c81df43ef936ffd36290d45a79429630c1b4b
diff --git a/core/java/com/android/internal/os/InstallerConnection.java b/core/java/com/android/internal/os/InstallerConnection.java
index 13d046e..830da79 100644
--- a/core/java/com/android/internal/os/InstallerConnection.java
+++ b/core/java/com/android/internal/os/InstallerConnection.java
@@ -21,6 +21,8 @@
import android.os.SystemClock;
import android.util.Slog;
+import com.android.internal.util.Preconditions;
+
import libcore.io.IoUtils;
import libcore.io.Streams;
@@ -42,11 +44,22 @@
private OutputStream mOut;
private LocalSocket mSocket;
+ private volatile Object mWarnIfHeld;
+
private final byte buf[] = new byte[1024];
public InstallerConnection() {
}
+ /**
+ * Yell loudly if someone tries making future calls while holding a lock on
+ * the given object.
+ */
+ public void setWarnIfHeld(Object warnIfHeld) {
+ Preconditions.checkState(mWarnIfHeld == null);
+ mWarnIfHeld = Preconditions.checkNotNull(warnIfHeld);
+ }
+
public synchronized String transact(String cmd) {
if (!connect()) {
Slog.e(TAG, "connection failed");
@@ -84,6 +97,11 @@
}
public int execute(String cmd) {
+ if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
+ Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
+ + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
+ }
+
String res = transact(cmd);
try {
return Integer.parseInt(res);
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 87ae3dc..a7879c6 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -1440,7 +1440,7 @@
mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25,
null);
mConnector.setDebug(true);
- mConnector.setLockWarning(mLock);
+ mConnector.setWarnIfHeld(mLock);
Thread thread = new Thread(mConnector, VOLD_TAG);
thread.start();
diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java
index 3a6fa05..e6b6074 100644
--- a/services/core/java/com/android/server/NativeDaemonConnector.java
+++ b/services/core/java/com/android/server/NativeDaemonConnector.java
@@ -25,10 +25,10 @@
import android.os.PowerManager;
import android.os.SystemClock;
import android.util.LocalLog;
-import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
import com.google.android.collect.Lists;
import java.io.FileDescriptor;
@@ -58,7 +58,7 @@
private LocalLog mLocalLog;
private volatile boolean mDebug = false;
- private volatile Object mLockWarning;
+ private volatile Object mWarnIfHeld;
private final ResponseQueue mResponseQueue;
@@ -110,11 +110,12 @@
}
/**
- * Yell loudly if someone tries making future {@link #execute(Command)} calls while holding a
- * lock on the given object.
+ * Yell loudly if someone tries making future {@link #execute(Command)}
+ * calls while holding a lock on the given object.
*/
- public void setLockWarning(Object lockWarning) {
- mLockWarning = lockWarning;
+ public void setWarnIfHeld(Object warnIfHeld) {
+ Preconditions.checkState(mWarnIfHeld == null);
+ mWarnIfHeld = Preconditions.checkNotNull(warnIfHeld);
}
@Override
@@ -404,8 +405,9 @@
*/
public NativeDaemonEvent[] executeForList(long timeoutMs, String cmd, Object... args)
throws NativeDaemonConnectorException {
- if (mLockWarning != null && Thread.holdsLock(mLockWarning)) {
- Log.wtf(TAG, "Calling thread is holding lock " + mLockWarning, new Throwable());
+ if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
+ Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
+ + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
}
final long startTime = SystemClock.elapsedRealtime();
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index d867616..150c849 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -53,6 +53,14 @@
mInstaller = new InstallerConnection();
}
+ /**
+ * Yell loudly if someone tries making future calls while holding a lock on
+ * the given object.
+ */
+ public void setWarnIfHeld(Object warnIfHeld) {
+ mInstaller.setWarnIfHeld(warnIfHeld);
+ }
+
@Override
public void onStart() {
Slog.i(TAG, "Waiting for installd to be ready.");
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c497ad4..08f9bd5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2391,6 +2391,11 @@
// tidy.
Runtime.getRuntime().gc();
+ // The initial scanning above does many calls into installd while
+ // holding the mPackages lock, but we're mostly interested in yelling
+ // once we have a booted system.
+ mInstaller.setWarnIfHeld(mPackages);
+
// Expose private service for system components to use.
LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());
}