Merge "Fix RemoteListenerHelper vs. HAL deadlock" into oc-dr1-dev
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 7275461..a4e673d 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -243,8 +243,9 @@
 
     private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
 
-    private GnssLocationProvider.GnssBatchingProvider mGnssBatchingProvider;
     private GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
+
+    private GnssLocationProvider.GnssBatchingProvider mGnssBatchingProvider;
     private IBatchedLocationCallback mGnssBatchingCallback;
     private LinkedCallback mGnssBatchingDeathCallback;
     private boolean mGnssBatchingInProgress = false;
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 83bb17e..cdf25cf 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -1754,20 +1754,32 @@
     }
 
     /**
-     * called from native code - Gps measurements callback
+     * called from native code - GNSS measurements callback
      */
     private void reportMeasurementData(GnssMeasurementsEvent event) {
         if (!mItarSpeedLimitExceeded) {
-            mGnssMeasurementsProvider.onMeasurementsAvailable(event);
+            // send to handler to allow native to return quickly
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mGnssMeasurementsProvider.onMeasurementsAvailable(event);
+                }
+            });
         }
     }
 
     /**
-     * called from native code - GPS navigation message callback
+     * called from native code - GNSS navigation message callback
      */
     private void reportNavigationMessage(GnssNavigationMessage event) {
         if (!mItarSpeedLimitExceeded) {
-            mGnssNavigationMessageProvider.onNavigationMessageAvailable(event);
+            // send to handler to allow native to return quickly
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mGnssNavigationMessageProvider.onNavigationMessageAvailable(event);
+                }
+            });
         }
     }
 
diff --git a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
index caf1d6c..924520b 100644
--- a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
@@ -54,9 +54,8 @@
     }
 
     public void onGpsEnabledChanged() {
-        if (tryUpdateRegistrationWithService()) {
-            updateResult();
-        }
+        tryUpdateRegistrationWithService();
+        updateResult();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java b/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
index 8d21928..df3c49b 100644
--- a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
+++ b/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
@@ -55,9 +55,8 @@
     }
 
     public void onGpsEnabledChanged() {
-        if (tryUpdateRegistrationWithService()) {
-            updateResult();
-        }
+        tryUpdateRegistrationWithService();
+        updateResult();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/location/RemoteListenerHelper.java b/services/core/java/com/android/server/location/RemoteListenerHelper.java
index ec2828b..f51bc87 100644
--- a/services/core/java/com/android/server/location/RemoteListenerHelper.java
+++ b/services/core/java/com/android/server/location/RemoteListenerHelper.java
@@ -25,6 +25,7 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import java.lang.Runnable;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -45,7 +46,7 @@
 
     private final Map<IBinder, LinkedListener> mListenerMap = new HashMap<>();
 
-    private boolean mIsRegistered;
+    private boolean mIsRegistered;  // must access only on handler thread
     private boolean mHasIsSupported;
     private boolean mIsSupported;
 
@@ -83,12 +84,12 @@
             } else if (mHasIsSupported && !mIsSupported) {
                 result = RESULT_NOT_SUPPORTED;
             } else if (!isGpsEnabled()) {
-                result = RESULT_GPS_LOCATION_DISABLED;
-            } else if (!tryRegister()) {
                 // only attempt to register if GPS is enabled, otherwise we will register once GPS
                 // becomes available
-                result = RESULT_INTERNAL_ERROR;
+                result = RESULT_GPS_LOCATION_DISABLED;
             } else if (mHasIsSupported && mIsSupported) {
+                tryRegister();
+                // initially presume success, possible internal error could follow asynchornously
                 result = RESULT_SUCCESS;
             } else {
                 // at this point if the supported flag is not set, the notification will be sent
@@ -117,8 +118,8 @@
 
     protected abstract boolean isAvailableInPlatform();
     protected abstract boolean isGpsEnabled();
-    protected abstract boolean registerWithService();
-    protected abstract void unregisterFromService();
+    protected abstract boolean registerWithService(); // must access only on handler thread
+    protected abstract void unregisterFromService(); // must access only on handler thread
     protected abstract ListenerOperation<TListener> getHandlerOperation(int result);
 
     protected interface ListenerOperation<TListener extends IInterface> {
@@ -138,22 +139,16 @@
         }
     }
 
-    protected boolean tryUpdateRegistrationWithService() {
+    protected void tryUpdateRegistrationWithService() {
         synchronized (mListenerMap) {
             if (!isGpsEnabled()) {
                 tryUnregister();
-                return true;
+                return;
             }
             if (mListenerMap.isEmpty()) {
-                return true;
+                return;
             }
-            if (tryRegister()) {
-                // registration was successful, there is no need to update the state
-                return true;
-            }
-            ListenerOperation<TListener> operation = getHandlerOperation(RESULT_INTERNAL_ERROR);
-            foreachUnsafe(operation);
-            return false;
+            tryRegister();
         }
     }
 
@@ -180,19 +175,40 @@
         }
     }
 
-    private boolean tryRegister() {
-        if (!mIsRegistered) {
-            mIsRegistered = registerWithService();
-        }
-        return mIsRegistered;
+    private void tryRegister() {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                if (!mIsRegistered) {
+                    mIsRegistered = registerWithService();
+                }
+                if (!mIsRegistered) {
+                    // post back a failure
+                    mHandler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            synchronized (mListenerMap) {
+                                ListenerOperation<TListener> operation = getHandlerOperation(RESULT_INTERNAL_ERROR);
+                                foreachUnsafe(operation);
+                            }
+                        }
+                    });
+                }
+            }
+        });
     }
 
     private void tryUnregister() {
-        if (!mIsRegistered) {
-            return;
-        }
-        unregisterFromService();
-        mIsRegistered = false;
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                if (!mIsRegistered) {
+                    return;
+                }
+                unregisterFromService();
+                mIsRegistered = false;
+            }
+        });
     }
 
     private int calculateCurrentResultUnsafe() {