Import Android SDK Platform P [4697573]
/google/data/ro/projects/android/fetch_artifact \
--bid 4697573 \
--target sdk_phone_armv7-win_sdk \
sdk-repo-linux-sources-4697573.zip
AndroidVersion.ApiLevel has been modified to appear as 28
Change-Id: If80578c3c657366cc9cf75f8db13d46e2dd4e077
diff --git a/android/app/SystemServiceRegistry.java b/android/app/SystemServiceRegistry.java
index 4310434..1776eac 100644
--- a/android/app/SystemServiceRegistry.java
+++ b/android/app/SystemServiceRegistry.java
@@ -89,7 +89,6 @@
import android.net.lowpan.LowpanManager;
import android.net.nsd.INsdManager;
import android.net.nsd.NsdManager;
-import android.net.wifi.IRttManager;
import android.net.wifi.IWifiManager;
import android.net.wifi.IWifiScanner;
import android.net.wifi.RttManager;
@@ -116,7 +115,6 @@
import android.os.IUserManager;
import android.os.IncidentManager;
import android.os.PowerManager;
-import android.os.Process;
import android.os.RecoverySystem;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
@@ -162,6 +160,7 @@
import com.android.internal.policy.PhoneLayoutInflater;
import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* Manages all of the system services that can be returned by {@link Context#getSystemService}.
@@ -638,13 +637,13 @@
registerService(Context.WIFI_RTT_SERVICE, RttManager.class,
new CachedServiceFetcher<RttManager>() {
- @Override
- public RttManager createService(ContextImpl ctx) throws ServiceNotFoundException {
- IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_RTT_SERVICE);
- IRttManager service = IRttManager.Stub.asInterface(b);
- return new RttManager(ctx.getOuterContext(), service,
- ConnectivityThread.getInstanceLooper());
- }});
+ @Override
+ public RttManager createService(ContextImpl ctx) throws ServiceNotFoundException {
+ IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_RTT_RANGING_SERVICE);
+ IWifiRttManager service = IWifiRttManager.Stub.asInterface(b);
+ return new RttManager(ctx.getOuterContext(),
+ new WifiRttManager(ctx.getOuterContext(), service));
+ }});
registerService(Context.WIFI_RTT_RANGING_SERVICE, WifiRttManager.class,
new CachedServiceFetcher<WifiRttManager>() {
@@ -724,8 +723,9 @@
service = IPrintManager.Stub.asInterface(ServiceManager
.getServiceOrThrow(Context.PRINT_SERVICE));
}
- return new PrintManager(ctx.getOuterContext(), service, UserHandle.myUserId(),
- UserHandle.getAppId(Process.myUid()));
+ final int userId = ctx.getUserId();
+ final int appId = UserHandle.getAppId(ctx.getApplicationInfo().uid);
+ return new PrintManager(ctx.getOuterContext(), service, userId, appId);
}});
registerService(Context.COMPANION_DEVICE_SERVICE, CompanionDeviceManager.class,
@@ -780,12 +780,12 @@
}});
registerService(Context.TV_INPUT_SERVICE, TvInputManager.class,
- new StaticServiceFetcher<TvInputManager>() {
+ new CachedServiceFetcher<TvInputManager>() {
@Override
- public TvInputManager createService() throws ServiceNotFoundException {
+ public TvInputManager createService(ContextImpl ctx) throws ServiceNotFoundException {
IBinder iBinder = ServiceManager.getServiceOrThrow(Context.TV_INPUT_SERVICE);
ITvInputManager service = ITvInputManager.Stub.asInterface(iBinder);
- return new TvInputManager(service, UserHandle.myUserId());
+ return new TvInputManager(service, ctx.getUserId());
}});
registerService(Context.NETWORK_SCORE_SERVICE, NetworkScoreManager.class,
@@ -993,6 +993,10 @@
return new Object[sServiceCacheSize];
}
+ public static AtomicInteger[] createServiceInitializationStateArray() {
+ return new AtomicInteger[sServiceCacheSize];
+ }
+
/**
* Gets a system service from a given context.
*/
@@ -1041,19 +1045,95 @@
@SuppressWarnings("unchecked")
public final T getService(ContextImpl ctx) {
final Object[] cache = ctx.mServiceCache;
+
+ // Fast path. If it's already cached, just return it.
+ Object service = cache[mCacheIndex];
+ if (service != null) {
+ return (T) service;
+ }
+
+ // Slow path.
+ final AtomicInteger[] gates = ctx.mServiceInitializationStateArray;
+ final AtomicInteger gate;
+
synchronized (cache) {
- // Fetch or create the service.
- Object service = cache[mCacheIndex];
- if (service == null) {
+ // See if it's cached or not again, with the lock held this time.
+ service = cache[mCacheIndex];
+ if (service != null) {
+ return (T) service;
+ }
+
+ // Not initialized yet. Create an atomic boolean to control which thread should
+ // instantiate the service.
+ if (gates[mCacheIndex] != null) {
+ gate = gates[mCacheIndex];
+ } else {
+ gate = new AtomicInteger(ContextImpl.STATE_UNINITIALIZED);
+ gates[mCacheIndex] = gate;
+ }
+ }
+
+ // Not cached yet.
+ //
+ // Note multiple threads can reach here for the same service on the same context
+ // concurrently.
+ //
+ // Now we're going to instantiate the service, but do so without the cache held;
+ // otherwise it could deadlock. (b/71882178)
+ //
+ // However we still don't want to instantiate the same service multiple times, so
+ // use the atomic integer to ensure only one thread will call createService().
+
+ if (gate.compareAndSet(
+ ContextImpl.STATE_UNINITIALIZED, ContextImpl.STATE_INITIALIZING)) {
+ try {
+ // This thread is the first one to get here. Instantiate the service
+ // *without* the cache lock held.
try {
service = createService(ctx);
- cache[mCacheIndex] = service;
+
+ synchronized (cache) {
+ cache[mCacheIndex] = service;
+ }
} catch (ServiceNotFoundException e) {
onServiceNotFound(e);
}
+ } finally {
+ // Tell the all other threads that the cache is ready now.
+ // (But it's still be null in case of ServiceNotFoundException.)
+ synchronized (gate) {
+ gate.set(ContextImpl.STATE_READY);
+ gate.notifyAll();
+ }
}
- return (T)service;
+ return (T) service;
}
+ // Other threads will wait on the gate lock.
+ synchronized (gate) {
+ boolean interrupted = false;
+
+ // Note: We check whether "state == STATE_READY", not
+ // "cache[mCacheIndex] != null", because "cache[mCacheIndex] == null"
+ // is still a valid outcome in the ServiceNotFoundException case.
+ while (gate.get() != ContextImpl.STATE_READY) {
+ try {
+ gate.wait();
+ } catch (InterruptedException e) {
+ Log.w(TAG, "getService() interrupted");
+ interrupted = true;
+ }
+ }
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ // Now the first thread has initialized it.
+ // It may still be null if ServiceNotFoundException was thrown, but that shouldn't
+ // happen, so we'll just return null here in that case.
+ synchronized (cache) {
+ service = cache[mCacheIndex];
+ }
+ return (T) service;
}
public abstract T createService(ContextImpl ctx) throws ServiceNotFoundException;