Address SUPL connection requestRouteToHost deprecation

The method ConnectivityManager.requestRouteToHost() has long been
deprecated. The IAGnss.hal interface, implementation, and the
corresponding framework code must be changed to address this issue.
See b/25876485 for details and solution.

Bug: 25876485
Test: Tested with code instrumentation to verify that the
      @2.0::AGnss.hal dataConnOpen() method implementation
      is called with correct arguments.
Test: Verified @1.0::AGnss.hal backward compatibility on a
      Pixel 3 device.
Change-Id: Ide8030a3d792755a515c936d2fb40ad3726d8fb9
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 9c6cb20..b6954fc 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -177,10 +177,6 @@
     private static final int AGPS_SUPL_MODE_MSA = 0x02;
     private static final int AGPS_SUPL_MODE_MSB = 0x01;
 
-    // these need to match AGnssType enum in IAGnssCallback.hal
-    private static final int AGPS_TYPE_SUPL = 1;
-    private static final int AGPS_TYPE_C2K = 2;
-
     // Handler messages
     private static final int CHECK_LOCATION = 1;
     private static final int ENABLE = 2;
@@ -973,7 +969,8 @@
         if (mSuplServerHost != null
                 && mSuplServerPort > TCP_MIN_PORT
                 && mSuplServerPort <= TCP_MAX_PORT) {
-            native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
+            native_set_agps_server(GnssNetworkConnectivityHandler.AGPS_TYPE_SUPL,
+                    mSuplServerHost, mSuplServerPort);
         }
     }
 
@@ -1025,10 +1022,12 @@
 
             // TODO: remove the following native calls if we can make sure they are redundant.
             if (mSuplServerHost != null) {
-                native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
+                native_set_agps_server(GnssNetworkConnectivityHandler.AGPS_TYPE_SUPL,
+                        mSuplServerHost, mSuplServerPort);
             }
             if (mC2KServerHost != null) {
-                native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
+                native_set_agps_server(GnssNetworkConnectivityHandler.AGPS_TYPE_C2K,
+                        mC2KServerHost, mC2KServerPort);
             }
 
             mGnssMeasurementsProvider.onGpsEnabledChanged();
@@ -1575,8 +1574,8 @@
     }
 
     @NativeEntryPoint
-    private void reportAGpsStatus(int type, int status, byte[] ipaddr) {
-        mNetworkConnectivityHandler.onReportAGpsStatus(type, status, ipaddr);
+    private void reportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) {
+        mNetworkConnectivityHandler.onReportAGpsStatus(agpsType, agpsStatus, suplIpAddr);
     }
 
     @NativeEntryPoint
diff --git a/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java b/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
index 3903f2a..c38373f 100644
--- a/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
+++ b/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
@@ -68,6 +68,12 @@
     private static final int AGNSS_NET_CAPABILITY_NOT_METERED = 1 << 0;
     private static final int AGNSS_NET_CAPABILITY_NOT_ROAMING = 1 << 1;
 
+    // these need to match AGnssType enum in IAGnssCallback.hal
+    public static final int AGPS_TYPE_SUPL = 1;
+    public static final int AGPS_TYPE_C2K = 2;
+    private static final int AGPS_TYPE_EIMS = 3;
+    private static final int AGPS_TYPE_IMS = 4;
+
     // Default time limit in milliseconds for the ConnectivityManager to find a suitable
     // network with SUPL connectivity or report an error.
     private static final int SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS = 10 * 1000;
@@ -86,6 +92,7 @@
 
     private int mAGpsDataConnectionState;
     private InetAddress mAGpsDataConnectionIpAddr;
+    private int mAGpsType;
 
     private final Context mContext;
 
@@ -198,21 +205,11 @@
     /**
      * called from native code to update AGPS status
      */
-    public void onReportAGpsStatus(int type, int status, byte[] ipaddr) {
-        switch (status) {
+    public void onReportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) {
+        switch (agpsStatus) {
             case GPS_REQUEST_AGPS_DATA_CONN:
                 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
-                Log.v(TAG, "Received SUPL IP addr[]: " + Arrays.toString(ipaddr));
-                InetAddress connectionIpAddress = null;
-                if (ipaddr != null) {
-                    try {
-                        connectionIpAddress = InetAddress.getByAddress(ipaddr);
-                        if (DEBUG) Log.d(TAG, "IP address converted to: " + connectionIpAddress);
-                    } catch (UnknownHostException e) {
-                        Log.e(TAG, "Bad IP Address: " + ipaddr, e);
-                    }
-                }
-                requestSuplConnection(connectionIpAddress);
+                requestSuplConnection(agpsType, suplIpAddr);
                 break;
             case GPS_RELEASE_AGPS_DATA_CONN:
                 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
@@ -228,7 +225,7 @@
                 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
                 break;
             default:
-                if (DEBUG) Log.d(TAG, "Received Unknown AGPS status: " + status);
+                if (DEBUG) Log.d(TAG, "Received Unknown AGPS status: " + agpsStatus);
         }
     }
 
@@ -308,8 +305,8 @@
         };
     }
 
-    private void requestSuplConnection(InetAddress inetAddress) {
-        postEvent(() -> handleRequestSuplConnection(inetAddress));
+    private void requestSuplConnection(int agpsType, byte[] suplIpAddr) {
+        postEvent(() -> handleRequestSuplConnection(agpsType, suplIpAddr));
     }
 
     private void suplConnectionAvailable(Network network) {
@@ -435,8 +432,15 @@
                 // exception in the following call to native_agps_data_conn_open
                 apn = "dummy-apn";
             }
+
+            // Setting route to host is needed for GNSS HAL implementations earlier than
+            // @2.0::IAgnssCallback. The HAL @2.0::IAgnssCallback.agnssStatusCb() method does
+            // not require setting route to SUPL host and hence does not provide an IP address.
+            if (mAGpsDataConnectionIpAddr != null) {
+                setRouting();
+            }
+
             int apnIpType = getApnIpType(apn);
-            setRouting();
             if (DEBUG) {
                 String message = String.format(
                         "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s",
@@ -444,29 +448,40 @@
                         apnIpType);
                 Log.d(TAG, message);
             }
-            native_agps_data_conn_open(apn, apnIpType);
+            native_agps_data_conn_open(network.getNetworkHandle(), apn, apnIpType);
             mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
         }
     }
 
-    private void handleRequestSuplConnection(InetAddress address) {
+    private void handleRequestSuplConnection(int agpsType, byte[] suplIpAddr) {
+        mAGpsDataConnectionIpAddr = null;
+        mAGpsType = agpsType;
+        if (suplIpAddr != null) {
+            if (VERBOSE) Log.v(TAG, "Received SUPL IP addr[]: " + Arrays.toString(suplIpAddr));
+            try {
+                mAGpsDataConnectionIpAddr = InetAddress.getByAddress(suplIpAddr);
+                if (DEBUG) Log.d(TAG, "IP address converted to: " + mAGpsDataConnectionIpAddr);
+            } catch (UnknownHostException e) {
+                Log.e(TAG, "Bad IP Address: " + suplIpAddr, e);
+            }
+        }
+
         if (DEBUG) {
             String message = String.format(
-                    "requestSuplConnection, state=%s, address=%s",
+                    "requestSuplConnection, state=%s, agpsType=%s, address=%s",
                     agpsDataConnStateAsString(),
-                    address);
+                    agpsTypeAsString(agpsType),
+                    mAGpsDataConnectionIpAddr);
             Log.d(TAG, message);
         }
 
         if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
             return;
         }
-        mAGpsDataConnectionIpAddr = address;
         mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
 
         NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder();
-        requestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-        requestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
+        requestBuilder.addCapability(getNetworkCapability(mAGpsType));
         NetworkRequest request = requestBuilder.build();
         mConnMgr.requestNetwork(
                 request,
@@ -474,6 +489,20 @@
                 SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS);
     }
 
+    private int getNetworkCapability(int agpsType) {
+        switch (agpsType) {
+            case AGPS_TYPE_C2K:
+            case AGPS_TYPE_SUPL:
+                return NetworkCapabilities.NET_CAPABILITY_SUPL;
+            case AGPS_TYPE_EIMS:
+                return NetworkCapabilities.NET_CAPABILITY_EIMS;
+            case AGPS_TYPE_IMS:
+                return NetworkCapabilities.NET_CAPABILITY_IMS;
+            default:
+                throw new IllegalArgumentException("agpsType: " + agpsType);
+        }
+    }
+
     private void handleReleaseSuplConnection(int agpsDataConnStatus) {
         if (DEBUG) {
             String message = String.format(
@@ -486,8 +515,8 @@
         if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_CLOSED) {
             return;
         }
-        mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
 
+        mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
         mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback);
         switch (agpsDataConnStatus) {
             case GPS_AGPS_DATA_CONN_FAILED:
@@ -501,12 +530,9 @@
         }
     }
 
+    // TODO(25876485): Delete this method when all devices upgrade to HAL @2.0::IAGnssCallback
+    //                 interface which does not require setting route to host.
     private void setRouting() {
-        if (mAGpsDataConnectionIpAddr == null) {
-            return;
-        }
-
-        // TODO(25876485): replace the use of this deprecated API
         boolean result = mConnMgr.requestRouteToHostAddress(
                 ConnectivityManager.TYPE_MOBILE_SUPL,
                 mAGpsDataConnectionIpAddr);
@@ -564,6 +590,21 @@
         }
     }
 
+    private String agpsTypeAsString(int agpsType) {
+        switch (agpsType) {
+            case AGPS_TYPE_SUPL:
+                return "SUPL";
+            case AGPS_TYPE_C2K:
+                return "C2K";
+            case AGPS_TYPE_EIMS:
+                return "EIMS";
+            case AGPS_TYPE_IMS:
+                return "IMS";
+            default:
+                return "<Unknown>";
+        }
+    }
+
     private int getApnIpType(String apn) {
         ensureInHandlerThread();
         if (apn == null) {
@@ -614,7 +655,7 @@
     }
 
     // AGPS support
-    private native void native_agps_data_conn_open(String apn, int apnIpType);
+    private native void native_agps_data_conn_open(long networkHandle, String apn, int apnIpType);
 
     private native void native_agps_data_conn_closed();
 
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 729aed1..6d8fc1c 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -104,14 +104,12 @@
 using android::hardware::Return;
 using android::hardware::Void;
 using android::hardware::hidl_vec;
+using android::hardware::hidl_string;
 using android::hardware::hidl_death_recipient;
 using android::hardware::gnss::V1_0::GnssConstellationType;
 using android::hardware::gnss::V1_0::GnssLocation;
 using android::hardware::gnss::V1_0::GnssLocationFlags;
 
-using android::hardware::gnss::V1_0::IAGnss;
-using android::hardware::gnss::V1_0::IAGnssCallback;
-using android::hardware::gnss::V1_0::IAGnssCallback;
 using android::hardware::gnss::V1_0::IAGnssRilCallback;
 using android::hardware::gnss::V1_0::IGnssBatching;
 using android::hardware::gnss::V1_0::IGnssBatchingCallback;
@@ -145,6 +143,10 @@
 using IGnssMeasurementCallback_V2_0 = android::hardware::gnss::V2_0::IGnssMeasurementCallback;
 using IAGnssRil_V1_0 = android::hardware::gnss::V1_0::IAGnssRil;
 using IAGnssRil_V2_0 = android::hardware::gnss::V2_0::IAGnssRil;
+using IAGnss_V1_0 = android::hardware::gnss::V1_0::IAGnss;
+using IAGnss_V2_0 = android::hardware::gnss::V2_0::IAGnss;
+using IAGnssCallback_V1_0 = android::hardware::gnss::V1_0::IAGnssCallback;
+using IAGnssCallback_V2_0 = android::hardware::gnss::V2_0::IAGnssCallback;
 
 using IMeasurementCorrections =
     android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections;
@@ -171,7 +173,8 @@
 sp<IAGnssRil_V1_0> agnssRilIface = nullptr;
 sp<IAGnssRil_V2_0> agnssRilIface_V2_0 = nullptr;
 sp<IGnssGeofencing> gnssGeofencingIface = nullptr;
-sp<IAGnss> agnssIface = nullptr;
+sp<IAGnss_V1_0> agnssIface = nullptr;
+sp<IAGnss_V2_0> agnssIface_V2_0 = nullptr;
 sp<IGnssBatching> gnssBatchingIface = nullptr;
 sp<IGnssDebug> gnssDebugIface = nullptr;
 sp<IGnssConfiguration_V1_0> gnssConfigurationIface = nullptr;
@@ -310,6 +313,34 @@
     }
 }
 
+struct ScopedJniString {
+    ScopedJniString(JNIEnv* env, jstring javaString) : mEnv(env), mJavaString(javaString) {
+        mNativeString = mEnv->GetStringUTFChars(mJavaString, nullptr);
+    }
+
+    ~ScopedJniString() {
+        if (mNativeString != nullptr) {
+            mEnv->ReleaseStringUTFChars(mJavaString, mNativeString);
+        }
+    }
+
+    const char* c_str() const {
+        return mNativeString;
+    }
+
+    operator hidl_string() const {
+        return hidl_string(mNativeString);
+    }
+
+private:
+    ScopedJniString(const ScopedJniString&) = delete;
+    ScopedJniString& operator=(const ScopedJniString&) = delete;
+
+    JNIEnv* mEnv;
+    jstring mJavaString;
+    const char* mNativeString;
+};
+
 class ScopedJniThreadAttach {
 public:
     ScopedJniThreadAttach() {
@@ -1038,21 +1069,21 @@
 }
 
 /*
- * AGnssCallback implements callback methods required by the IAGnss interface.
+ * AGnssCallback_V1_0 implements callback methods required by the IAGnssCallback 1.0 interface.
  */
-struct AGnssCallback : public IAGnssCallback {
+struct AGnssCallback_V1_0 : public IAGnssCallback_V1_0 {
     // Methods from ::android::hardware::gps::V1_0::IAGnssCallback follow.
     Return<void> agnssStatusIpV6Cb(
-      const IAGnssCallback::AGnssStatusIpV6& agps_status) override;
+      const IAGnssCallback_V1_0::AGnssStatusIpV6& agps_status) override;
 
     Return<void> agnssStatusIpV4Cb(
-      const IAGnssCallback::AGnssStatusIpV4& agps_status) override;
+      const IAGnssCallback_V1_0::AGnssStatusIpV4& agps_status) override;
  private:
     jbyteArray convertToIpV4(uint32_t ip);
 };
 
-Return<void> AGnssCallback::agnssStatusIpV6Cb(
-        const IAGnssCallback::AGnssStatusIpV6& agps_status) {
+Return<void> AGnssCallback_V1_0::agnssStatusIpV6Cb(
+        const IAGnssCallback_V1_0::AGnssStatusIpV6& agps_status) {
     JNIEnv* env = getJniEnv();
     jbyteArray byteArray = nullptr;
 
@@ -1085,8 +1116,8 @@
     return Void();
 }
 
-Return<void> AGnssCallback::agnssStatusIpV4Cb(
-        const IAGnssCallback::AGnssStatusIpV4& agps_status) {
+Return<void> AGnssCallback_V1_0::agnssStatusIpV4Cb(
+        const IAGnssCallback_V1_0::AGnssStatusIpV4& agps_status) {
     JNIEnv* env = getJniEnv();
     jbyteArray byteArray = nullptr;
 
@@ -1117,7 +1148,7 @@
     return Void();
 }
 
-jbyteArray AGnssCallback::convertToIpV4(uint32_t ip) {
+jbyteArray AGnssCallback_V1_0::convertToIpV4(uint32_t ip) {
     if (INADDR_NONE == ip) {
         return nullptr;
     }
@@ -1137,6 +1168,23 @@
 }
 
 /*
+ * AGnssCallback_V2_0 implements callback methods required by the IAGnssCallback 2.0 interface.
+ */
+struct AGnssCallback_V2_0 : public IAGnssCallback_V2_0 {
+    // Methods from ::android::hardware::gps::V2_0::IAGnssCallback follow.
+    Return<void> agnssStatusCb(IAGnssCallback_V2_0::AGnssType type,
+        IAGnssCallback_V2_0::AGnssStatusValue status) override;
+};
+
+Return<void> AGnssCallback_V2_0::agnssStatusCb(IAGnssCallback_V2_0::AGnssType type,
+        IAGnssCallback_V2_0::AGnssStatusValue status) {
+    JNIEnv* env = getJniEnv();
+    env->CallVoidMethod(mCallbacksObj, method_reportAGpsStatus, type, status, nullptr);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Void();
+}
+
+/*
  * AGnssRilCallback implements the callback methods required by the AGnssRil
  * interface.
  */
@@ -1303,11 +1351,20 @@
         }
     }
 
-    auto gnssAgnss = gnssHal->getExtensionAGnss();
-    if (!gnssAgnss.isOk()) {
-        ALOGD("Unable to get a handle to AGnss");
+    if (gnssHal_V2_0 != nullptr) {
+        auto agnss_V2_0 = gnssHal_V2_0->getExtensionAGnss_2_0();
+        if (!agnss_V2_0.isOk()) {
+            ALOGD("Unable to get a handle to AGnss_V2_0");
+        } else {
+            agnssIface_V2_0 = agnss_V2_0;
+        }
     } else {
-        agnssIface = gnssAgnss;
+        auto agnss_V1_0 = gnssHal->getExtensionAGnss();
+        if (!agnss_V1_0.isOk()) {
+            ALOGD("Unable to get a handle to AGnss");
+        } else {
+            agnssIface = agnss_V1_0;
+        }
     }
 
     auto gnssNavigationMessage = gnssHal->getExtensionGnssNavigationMessage();
@@ -1453,11 +1510,14 @@
         }
     }
 
-    sp<IAGnssCallback> aGnssCbIface = new AGnssCallback();
-    if (agnssIface != nullptr) {
+    if (agnssIface_V2_0 != nullptr) {
+        sp<IAGnssCallback_V2_0> aGnssCbIface = new AGnssCallback_V2_0();
+        agnssIface_V2_0->setCallback(aGnssCbIface);
+    } else if (agnssIface != nullptr) {
+        sp<IAGnssCallback_V1_0> aGnssCbIface = new AGnssCallback_V1_0();
         agnssIface->setCallback(aGnssCbIface);
     } else {
-        ALOGI("Unable to Initialize AGnss interface\n");
+        ALOGI("Unable to initialize AGnss interface\n");
     }
 
     sp<IGnssGeofenceCallback> gnssGeofencingCbIface = new GnssGeofenceCallback();
@@ -1586,9 +1646,8 @@
         return;
     }
 
-    const char *setid = env->GetStringUTFChars(setid_string, nullptr);
-    agnssRilIface->setSetId((IAGnssRil_V1_0::SetIDType)type, setid);
-    env->ReleaseStringUTFChars(setid_string, setid);
+    ScopedJniString jniSetId{env, setid_string};
+    agnssRilIface->setSetId((IAGnssRil_V1_0::SetIDType)type, jniSetId);
 }
 
 static jint android_location_GnssLocationProvider_read_nmea(JNIEnv* env, jobject /* obj */,
@@ -1676,68 +1735,126 @@
     env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
 }
 
-static void android_location_GnssNetworkConnectivityHandler_agps_data_conn_open(
-        JNIEnv* env, jobject /* obj */, jstring apn, jint apnIpType) {
-    if (agnssIface == nullptr) {
-        ALOGE("no AGPS interface in agps_data_conn_open");
-        return;
-    }
-    if (apn == nullptr) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", nullptr);
-        return;
-    }
+struct AGnssDispatcher {
+    static void dataConnOpen(sp<IAGnss_V1_0> agnssIface, JNIEnv* env, jstring apn, jint apnIpType);
+    static void dataConnOpen(sp<IAGnss_V2_0> agnssIface_V2_0, JNIEnv* env, jlong networkHandle,
+            jstring apn, jint apnIpType);
 
-    const char *apnStr = env->GetStringUTFChars(apn, nullptr);
+    template <class T>
+    static void dataConnClosed(sp<T> agnssIface);
 
-    auto result = agnssIface->dataConnOpen(apnStr, static_cast<IAGnss::ApnIpType>(apnIpType));
+    template <class T>
+    static void dataConnFailed(sp<T> agnssIface);
+
+    template <class T, class U>
+    static void setServer(sp<T> agnssIface, JNIEnv* env, jint type, jstring hostname, jint port);
+
+private:
+    AGnssDispatcher() = delete;
+    AGnssDispatcher(const AGnssDispatcher&) = delete;
+    AGnssDispatcher& operator=(const AGnssDispatcher&) = delete;
+};
+
+void AGnssDispatcher::dataConnOpen(sp<IAGnss_V1_0> agnssIface, JNIEnv* env, jstring apn,
+        jint apnIpType) {
+    ScopedJniString jniApn{env, apn};
+    auto result = agnssIface->dataConnOpen(jniApn,
+            static_cast<IAGnss_V1_0::ApnIpType>(apnIpType));
     if (!result.isOk() || !result){
         ALOGE("%s: Failed to set APN and its IP type", __func__);
     }
-    env->ReleaseStringUTFChars(apn, apnStr);
 }
 
-static void android_location_GnssNetworkConnectivityHandler_agps_data_conn_closed(JNIEnv* /* env */,
-                                                                       jobject /* obj */) {
-    if (agnssIface == nullptr) {
-        ALOGE("%s: AGPS interface not supported", __func__);
-        return;
+void AGnssDispatcher::dataConnOpen(sp<IAGnss_V2_0> agnssIface_V2_0, JNIEnv* env,
+        jlong networkHandle, jstring apn, jint apnIpType) {
+    ScopedJniString jniApn{env, apn};
+    auto result = agnssIface_V2_0->dataConnOpen(static_cast<uint64_t>(networkHandle), jniApn,
+            static_cast<IAGnss_V2_0::ApnIpType>(apnIpType));
+    if (!result.isOk() || !result){
+        ALOGE("%s: Failed to set APN and its IP type", __func__);
     }
+}
 
+template<class T>
+void AGnssDispatcher::dataConnClosed(sp<T> agnssIface) {
     auto result = agnssIface->dataConnClosed();
     if (!result.isOk() || !result) {
         ALOGE("%s: Failed to close AGnss data connection", __func__);
     }
 }
 
-static void android_location_GnssNetworkConnectivityHandler_agps_data_conn_failed(JNIEnv* /* env */,
-                                                                       jobject /* obj */) {
-    if (agnssIface == nullptr) {
-        ALOGE("%s: AGPS interface not supported", __func__);
-        return;
-    }
-
+template<class T>
+void AGnssDispatcher::dataConnFailed(sp<T> agnssIface) {
     auto result = agnssIface->dataConnFailed();
     if (!result.isOk() || !result) {
         ALOGE("%s: Failed to notify unavailability of AGnss data connection", __func__);
     }
 }
 
-static void android_location_GnssLocationProvider_set_agps_server(JNIEnv* env, jobject /* obj */,
-        jint type, jstring hostname, jint port) {
-    if (agnssIface == nullptr) {
-        ALOGE("no AGPS interface in set_agps_server");
-        return;
-    }
-
-    const char *c_hostname = env->GetStringUTFChars(hostname, nullptr);
-    auto result = agnssIface->setServer(static_cast<IAGnssCallback::AGnssType>(type),
-                                       c_hostname,
-                                       port);
+template <class T, class U>
+void AGnssDispatcher::setServer(sp<T> agnssIface, JNIEnv* env, jint type, jstring hostname,
+        jint port) {
+    ScopedJniString jniHostName{env, hostname};
+    auto result = agnssIface->setServer(static_cast<typename U::AGnssType>(type),
+            jniHostName, port);
     if (!result.isOk() || !result) {
         ALOGE("%s: Failed to set AGnss host name and port", __func__);
     }
+}
 
-    env->ReleaseStringUTFChars(hostname, c_hostname);
+static void android_location_GnssNetworkConnectivityHandler_agps_data_conn_open(
+        JNIEnv* env, jobject /* obj */, jlong networkHandle, jstring apn, jint apnIpType) {
+    if (apn == nullptr) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", nullptr);
+        return;
+    }
+
+    if (agnssIface_V2_0 != nullptr) {
+        AGnssDispatcher::dataConnOpen(agnssIface_V2_0, env, networkHandle, apn, apnIpType);
+    } else if (agnssIface != nullptr) {
+        AGnssDispatcher::dataConnOpen(agnssIface, env, apn, apnIpType);
+    } else {
+        ALOGE("%s: AGPS interface not supported", __func__);
+        return;
+    }
+}
+
+static void android_location_GnssNetworkConnectivityHandler_agps_data_conn_closed(JNIEnv* /* env */,
+                                                                       jobject /* obj */) {
+    if (agnssIface_V2_0 != nullptr) {
+        AGnssDispatcher::dataConnClosed(agnssIface_V2_0);
+    } else if (agnssIface != nullptr) {
+        AGnssDispatcher::dataConnClosed(agnssIface);
+    } else {
+        ALOGE("%s: AGPS interface not supported", __func__);
+        return;
+    }
+}
+
+static void android_location_GnssNetworkConnectivityHandler_agps_data_conn_failed(JNIEnv* /* env */,
+                                                                       jobject /* obj */) {
+    if (agnssIface_V2_0 != nullptr) {
+        AGnssDispatcher::dataConnFailed(agnssIface_V2_0);
+    } else if (agnssIface != nullptr) {
+        AGnssDispatcher::dataConnFailed(agnssIface);
+    } else {
+        ALOGE("%s: AGPS interface not supported", __func__);
+        return;
+    }
+}
+
+static void android_location_GnssLocationProvider_set_agps_server(JNIEnv* env, jobject /* obj */,
+        jint type, jstring hostname, jint port) {
+    if (agnssIface_V2_0 != nullptr) {
+        AGnssDispatcher::setServer<IAGnss_V2_0, IAGnssCallback_V2_0>(agnssIface_V2_0, env, type,
+                hostname, port);
+    } else if (agnssIface != nullptr) {
+        AGnssDispatcher::setServer<IAGnss_V1_0, IAGnssCallback_V1_0>(agnssIface, env, type,
+                hostname, port);
+    } else {
+        ALOGE("%s: AGPS interface not supported", __func__);
+        return;
+    }
 }
 
 static void android_location_GnssLocationProvider_send_ni_response(JNIEnv* /* env */,
@@ -1832,41 +1949,37 @@
                                                                        jstring apn,
                                                                        jlong networkHandle,
                                                                        jshort capabilities) {
-    if (agnssRilIface == nullptr) {
-        ALOGE("AGnssRilInterface does not exist");
-        return;
-    }
-
-    const char *c_apn = env->GetStringUTFChars(apn, nullptr);
-    const android::hardware::hidl_string hidl_apn{c_apn};
     if (agnssRilIface_V2_0 != nullptr) {
+        ScopedJniString jniApn{env, apn};
         IAGnssRil_V2_0::NetworkAttributes networkAttributes = {
             .networkHandle = static_cast<uint64_t>(networkHandle),
             .isConnected = static_cast<bool>(connected),
             .capabilities = static_cast<uint16_t>(capabilities),
-            .apn = hidl_apn
+            .apn = jniApn
         };
 
         auto result = agnssRilIface_V2_0->updateNetworkState_2_0(networkAttributes);
         if (!result.isOk() || !result) {
             ALOGE("updateNetworkState_2_0 failed");
         }
-    } else {
+    } else if (agnssRilIface != nullptr) {
+        ScopedJniString jniApn{env, apn};
+        hidl_string hidlApn{jniApn};
         auto result = agnssRilIface->updateNetworkState(connected,
                 static_cast<IAGnssRil_V1_0::NetworkType>(type), roaming);
         if (!result.isOk() || !result) {
             ALOGE("updateNetworkState failed");
         }
 
-        if (!hidl_apn.empty()) {
-            result = agnssRilIface->updateNetworkAvailability(available, hidl_apn);
+        if (!hidlApn.empty()) {
+            result = agnssRilIface->updateNetworkAvailability(available, hidlApn);
             if (!result.isOk() || !result) {
                 ALOGE("updateNetworkAvailability failed");
             }
         }
+    } else {
+        ALOGE("AGnssRilInterface does not exist");
     }
-
-    env->ReleaseStringUTFChars(apn, c_apn);
 }
 
 static jboolean android_location_GnssGeofenceProvider_is_geofence_supported(
@@ -2540,7 +2653,7 @@
             "(ZIZZLjava/lang/String;JS)V",
             reinterpret_cast<void *>(android_location_GnssNetworkConnectivityHandler_update_network_state)},
     {"native_agps_data_conn_open",
-            "(Ljava/lang/String;I)V",
+            "(JLjava/lang/String;I)V",
             reinterpret_cast<void *>(android_location_GnssNetworkConnectivityHandler_agps_data_conn_open)},
     {"native_agps_data_conn_closed",
             "()V",