Merge "Context.getSystemService() shouldn't return null..." into rvc-dev

This commit is contained in:
Makoto Onuki
2020-04-08 19:33:30 +00:00
committed by Android (Google) Code Review

View File

@@ -1658,6 +1658,9 @@ public final class SystemServiceRegistry {
public final T getService(ContextImpl ctx) { public final T getService(ContextImpl ctx) {
final Object[] cache = ctx.mServiceCache; final Object[] cache = ctx.mServiceCache;
final int[] gates = ctx.mServiceInitializationStateArray; final int[] gates = ctx.mServiceInitializationStateArray;
boolean interrupted = false;
T ret = null;
for (;;) { for (;;) {
boolean doInitialize = false; boolean doInitialize = false;
@@ -1665,7 +1668,8 @@ public final class SystemServiceRegistry {
// Return it if we already have a cached instance. // Return it if we already have a cached instance.
T service = (T) cache[mCacheIndex]; T service = (T) cache[mCacheIndex];
if (service != null || gates[mCacheIndex] == ContextImpl.STATE_NOT_FOUND) { if (service != null || gates[mCacheIndex] == ContextImpl.STATE_NOT_FOUND) {
return service; ret = service;
break; // exit the for (;;)
} }
// If we get here, there's no cached instance. // If we get here, there's no cached instance.
@@ -1708,24 +1712,33 @@ public final class SystemServiceRegistry {
cache.notifyAll(); cache.notifyAll();
} }
} }
return service; ret = service;
break; // exit the for (;;)
} }
// The other threads will wait for the first thread to call notifyAll(), // The other threads will wait for the first thread to call notifyAll(),
// and go back to the top and retry. // and go back to the top and retry.
synchronized (cache) { synchronized (cache) {
// Repeat until the state becomes STATE_READY or STATE_NOT_FOUND.
// We can't respond to interrupts here; just like we can't in the "doInitialize"
// path, so we remember the interrupt state here and re-interrupt later.
while (gates[mCacheIndex] < ContextImpl.STATE_READY) { while (gates[mCacheIndex] < ContextImpl.STATE_READY) {
try { try {
// Clear the interrupt state.
interrupted |= Thread.interrupted();
cache.wait(); cache.wait();
} catch (InterruptedException e) { } catch (InterruptedException e) {
// This shouldn't normally happen, but if someone interrupts the // This shouldn't normally happen, but if someone interrupts the
// thread, it will. // thread, it will.
Slog.wtf(TAG, "getService() interrupted"); Slog.w(TAG, "getService() interrupted");
Thread.currentThread().interrupt(); interrupted = true;
return null;
} }
} }
} }
} }
if (interrupted) {
Thread.currentThread().interrupt();
}
return ret;
} }
public abstract T createService(ContextImpl ctx) throws ServiceNotFoundException; public abstract T createService(ContextImpl ctx) throws ServiceNotFoundException;