Cherry-picking the following 3 getContentProviderImpl() CLs
- http://ag/5163037
Fix a race in AMS.getContentProviderImpl().
If the provider process has just been killed by AM but appDiedLocked()
hasn't been called yet, this method would wait on the wrong
ContentProviderRecord.
- http://ag/5201125
Fix getContentProviderImpl() permission issue
- http://ag/5284403
Add timeout to AMS.getContentProviderImpl()
Bug: 116876013
Bug: 110030490
Test: manual test with the following debug code:
+ final String prop = "debug.am.provider.fake-kill." + cpr.proc.processName;
+ if (SystemProperties.getBoolean(prop, false)) {
+ cpr.proc.kill("fake-kill", true);
+ SystemProperties.set(prop, "0");
+ }
providerRunning = !cpr.proc.killed;
Then:
setprop debug.am.provider.fake-kill.android.process.acore 1
And launch the contacts app when acore is already running, and make sure
the timeout log shows up on logcat.
Test: Also do it with work profile contacts
Change-Id: I765d61a1b2719a92dff7db0162335f2c09c33421
Merged-in: I2c4ba1e87c2d47f2013befff10c49b3dc337a9a7
Merged-in: Ia35a9d36a34257873edbdcaefcf85d2373f3295e
Merged-in: Id5e7fff228d777eb0d1804654600d9ea156e36fd
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 145c1c9..d149651 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -581,6 +581,12 @@
// before we decide it must be hung.
static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10*1000;
+ /**
+ * How long we wait for an provider to be published. Should be longer than
+ * {@link #CONTENT_PROVIDER_PUBLISH_TIMEOUT}.
+ */
+ static final int CONTENT_PROVIDER_WAIT_TIMEOUT = 20 * 1000;
+
// How long we wait for a launched process to attach to the activity manager
// before we decide it's never going to come up for real, when the process was
// started with a wrapper for instrumentation (such as Valgrind) because it
@@ -12174,6 +12180,7 @@
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
+ boolean providerRunning = false;
synchronized(this) {
long startTime = SystemClock.uptimeMillis();
@@ -12213,7 +12220,26 @@
}
}
- boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
+ if (cpr != null && cpr.proc != null) {
+ providerRunning = !cpr.proc.killed;
+
+ // Note if killedByAm is also set, this means the provider process has just been
+ // killed by AM (in ProcessRecord.kill()), but appDiedLocked() hasn't been called
+ // yet. So we need to call appDiedLocked() here and let it clean up.
+ // (See the commit message on I2c4ba1e87c2d47f2013befff10c49b3dc337a9a7 to see
+ // how to test this case.)
+ if (cpr.proc.killed && cpr.proc.killedByAm) {
+ checkTime(startTime, "getContentProviderImpl: before appDied (killedByAm)");
+ final long iden = Binder.clearCallingIdentity();
+ try {
+ appDiedLocked(cpr.proc);
+ } finally {
+ Binder.restoreCallingIdentity(iden);
+ }
+ checkTime(startTime, "getContentProviderImpl: after appDied (killedByAm)");
+ }
+ }
+
if (providerRunning) {
cpi = cpr.info;
String msg;
@@ -12506,6 +12532,7 @@
}
// Wait for the provider to be published...
+ final long timeout = SystemClock.uptimeMillis() + CONTENT_PROVIDER_WAIT_TIMEOUT;
synchronized (cpr) {
while (cpr.provider == null) {
if (cpr.launchingApp == null) {
@@ -12520,13 +12547,22 @@
return null;
}
try {
+ final long wait = Math.max(0L, timeout - SystemClock.uptimeMillis());
if (DEBUG_MU) Slog.v(TAG_MU,
"Waiting to start provider " + cpr
- + " launchingApp=" + cpr.launchingApp);
+ + " launchingApp=" + cpr.launchingApp + " for " + wait + " ms");
if (conn != null) {
conn.waiting = true;
}
- cpr.wait();
+ cpr.wait(wait);
+ if (cpr.provider == null) {
+ Slog.wtf(TAG, "Timeout waiting for provider "
+ + cpi.applicationInfo.packageName + "/"
+ + cpi.applicationInfo.uid + " for provider "
+ + name
+ + " providerRunning=" + providerRunning);
+ return null;
+ }
} catch (InterruptedException ex) {
} finally {
if (conn != null) {