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;