Loading services/core/java/com/android/server/location/GpsLocationProvider.java +121 −35 Original line number Diff line number Diff line Loading @@ -83,6 +83,8 @@ import java.util.ArrayList; import java.util.Date; import java.util.Map.Entry; import java.util.Properties; import java.net.InetAddress; import java.net.UnknownHostException; /** * A GPS implementation of LocationProvider used by LocationManager. Loading Loading @@ -158,6 +160,12 @@ public class GpsLocationProvider implements LocationProviderInterface { private static final int AGPS_TYPE_SUPL = 1; private static final int AGPS_TYPE_C2K = 2; // these must match the definitions in gps.h private static final int APN_INVALID = 0; private static final int APN_IPV4 = 1; private static final int APN_IPV6 = 2; private static final int APN_IPV4V6 = 3; // for mAGpsDataConnectionState private static final int AGPS_DATA_CONNECTION_CLOSED = 0; private static final int AGPS_DATA_CONNECTION_OPENING = 1; Loading Loading @@ -312,8 +320,9 @@ public class GpsLocationProvider implements LocationProviderInterface { private Handler mHandler; private String mAGpsApn; private int mApnIpType; private int mAGpsDataConnectionState; private int mAGpsDataConnectionIpAddr; private InetAddress mAGpsDataConnectionIpAddr; private final ConnectivityManager mConnMgr; private final GpsNetInitiatedHandler mNIHandler; Loading Loading @@ -595,28 +604,28 @@ public class GpsLocationProvider implements LocationProviderInterface { if (info != null && info.getType() == ConnectivityManager.TYPE_MOBILE_SUPL && mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) { String apnName = info.getExtraInfo(); if (mNetworkAvailable) { String apnName = info.getExtraInfo(); if (apnName == null) { /* Assign a dummy value in the case of C2K as otherwise we will have a runtime exception in the following call to native_agps_data_conn_open*/ apnName = "dummy-apn"; } mAGpsApn = apnName; if (DEBUG) Log.d(TAG, "mAGpsDataConnectionIpAddr " + mAGpsDataConnectionIpAddr); if (mAGpsDataConnectionIpAddr != 0xffffffff) { boolean route_result; if (DEBUG) Log.d(TAG, "call requestRouteToHost"); route_result = mConnMgr.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_SUPL, mAGpsDataConnectionIpAddr); if (route_result == false) Log.d(TAG, "call requestRouteToHost failed"); mApnIpType = getApnIpType(apnName); setRouting(); if (DEBUG) { String message = String.format( "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s", mAGpsApn, mApnIpType); Log.d(TAG, message); } if (DEBUG) Log.d(TAG, "call native_agps_data_conn_open"); native_agps_data_conn_open(apnName); native_agps_data_conn_open(mAGpsApn, mApnIpType); mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; } else { if (DEBUG) Log.d(TAG, "call native_agps_data_conn_failed"); Log.e(TAG, "call native_agps_data_conn_failed, info: " + info); mAGpsApn = null; mApnIpType = APN_INVALID; mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; native_agps_data_conn_failed(); } Loading Loading @@ -1324,7 +1333,7 @@ public class GpsLocationProvider implements LocationProviderInterface { /** * called from native code to update AGPS status */ private void reportAGpsStatus(int type, int status, int ipaddr) { private void reportAGpsStatus(int type, int status, byte[] ipaddr) { switch (status) { case GPS_REQUEST_AGPS_DATA_CONN: if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN"); Loading @@ -1333,20 +1342,20 @@ public class GpsLocationProvider implements LocationProviderInterface { mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING; int result = mConnMgr.startUsingNetworkFeature( ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL); mAGpsDataConnectionIpAddr = ipaddr; if (ipaddr != null) { try { mAGpsDataConnectionIpAddr = InetAddress.getByAddress(ipaddr); } catch (UnknownHostException e) { Log.e(TAG, "Bad IP Address: " + ipaddr, e); mAGpsDataConnectionIpAddr = null; } } if (result == PhoneConstants.APN_ALREADY_ACTIVE) { if (DEBUG) Log.d(TAG, "PhoneConstants.APN_ALREADY_ACTIVE"); if (mAGpsApn != null) { Log.d(TAG, "mAGpsDataConnectionIpAddr " + mAGpsDataConnectionIpAddr); if (mAGpsDataConnectionIpAddr != 0xffffffff) { boolean route_result; if (DEBUG) Log.d(TAG, "call requestRouteToHost"); route_result = mConnMgr.requestRouteToHost( ConnectivityManager.TYPE_MOBILE_SUPL, mAGpsDataConnectionIpAddr); if (route_result == false) Log.d(TAG, "call requestRouteToHost failed"); } native_agps_data_conn_open(mAGpsApn); setRouting(); native_agps_data_conn_open(mAGpsApn, mApnIpType); mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; } else { Log.e(TAG, "mAGpsApn not set when receiving PhoneConstants.APN_ALREADY_ACTIVE"); Loading @@ -1370,6 +1379,7 @@ public class GpsLocationProvider implements LocationProviderInterface { ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL); native_agps_data_conn_closed(); mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; mAGpsDataConnectionIpAddr = null; } break; case GPS_AGPS_DATA_CONNECTED: Loading Loading @@ -1821,21 +1831,97 @@ public class GpsLocationProvider implements LocationProviderInterface { private String getSelectedApn() { Uri uri = Uri.parse("content://telephony/carriers/preferapn"); String apn = null; Cursor cursor = null; try { cursor = mContext.getContentResolver().query( uri, new String[] { "apn" }, null /* selection */, null /* selectionArgs */, Carriers.DEFAULT_SORT_ORDER); if (cursor != null && cursor.moveToFirst()) { return cursor.getString(0); } else { Log.e(TAG, "No APN found to select."); } } catch (Exception e) { Log.e(TAG, "Error encountered on selectiong the APN.", e); } finally { if (cursor != null) { cursor.close(); } } Cursor cursor = mContext.getContentResolver().query(uri, new String[] {"apn"}, null, null, Carriers.DEFAULT_SORT_ORDER); return null; } if (null != cursor) { private int getApnIpType(String apn) { if (apn == null) { return APN_INVALID; } // look for cached data to use if (apn.equals(mAGpsApn) && mApnIpType != APN_INVALID) { return mApnIpType; } String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn); Cursor cursor = null; try { if (cursor.moveToFirst()) { apn = cursor.getString(0); cursor = mContext.getContentResolver().query( Carriers.CONTENT_URI, new String[] { Carriers.PROTOCOL }, selection, null, Carriers.DEFAULT_SORT_ORDER); if (null != cursor && cursor.moveToFirst()) { return translateToApnIpType(cursor.getString(0), apn); } else { Log.e(TAG, "No entry found in query for APN: " + apn); } } catch (Exception e) { Log.e(TAG, "Error encountered on APN query for: " + apn, e); } finally { if (cursor != null) { cursor.close(); } } return apn; return APN_INVALID; } private int translateToApnIpType(String ipProtocol, String apn) { if ("IP".equals(ipProtocol)) { return APN_IPV4; } if ("IPV6".equals(ipProtocol)) { return APN_IPV6; } if ("IPV4V6".equals(ipProtocol)) { return APN_IPV4V6; } // we hit the default case so the ipProtocol is not recognized String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn); Log.e(TAG, message); return APN_INVALID; } private void setRouting() { if (mAGpsDataConnectionIpAddr == null) { return; } boolean result = mConnMgr.requestRouteToHostAddress( ConnectivityManager.TYPE_MOBILE_SUPL, mAGpsDataConnectionIpAddr); if (!result) { Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr); } else if (DEBUG) { Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr); } } @Override Loading Loading @@ -1897,7 +1983,7 @@ public class GpsLocationProvider implements LocationProviderInterface { private native String native_get_internal_state(); // AGPS Support private native void native_agps_data_conn_open(String apn); private native void native_agps_data_conn_open(String apn, int apnIpType); private native void native_agps_data_conn_closed(); private native void native_agps_data_conn_failed(); private native void native_agps_ni_message(byte [] msg, int length); Loading services/core/jni/com_android_server_location_GpsLocationProvider.cpp +105 −13 Original line number Diff line number Diff line Loading @@ -30,6 +30,8 @@ #include <string.h> #include <pthread.h> #include <linux/in.h> #include <linux/in6.h> static jobject mCallbacksObj = NULL; Loading Loading @@ -168,19 +170,98 @@ GpsXtraCallbacks sGpsXtraCallbacks = { create_thread_callback, }; static jbyteArray convert_to_ipv4(uint32_t ip, bool net_order) { if (INADDR_NONE == ip) { return NULL; } JNIEnv* env = AndroidRuntime::getJNIEnv(); jbyteArray byteArray = env->NewByteArray(4); if (byteArray == NULL) { ALOGE("Unable to allocate byte array for IPv4 address"); return NULL; } jbyte ipv4[4]; if (net_order) { memcpy(ipv4, &ip, sizeof(ipv4)); } else { //endianess transparent conversion from int to char[] ipv4[0] = (jbyte) (ip & 0xFF); ipv4[1] = (jbyte)((ip>>8) & 0xFF); ipv4[2] = (jbyte)((ip>>16) & 0xFF); ipv4[3] = (jbyte) (ip>>24); } env->SetByteArrayRegion(byteArray, 0, 4, (const jbyte*) ipv4); return byteArray; } static void agps_status_callback(AGpsStatus* agps_status) { JNIEnv* env = AndroidRuntime::getJNIEnv(); jbyteArray byteArray = NULL; bool isSupported = false; size_t status_size = agps_status->size; if (status_size == sizeof(AGpsStatus_v3)) { switch (agps_status->addr.ss_family) { case AF_INET: { struct sockaddr_in *in = (struct sockaddr_in*)&(agps_status->addr); uint32_t *pAddr = (uint32_t*)&(in->sin_addr); byteArray = convert_to_ipv4(*pAddr, true /* net_order */); if (byteArray != NULL) { isSupported = true; } } break; case AF_INET6: { struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&(agps_status->addr); byteArray = env->NewByteArray(16); if (byteArray != NULL) { env->SetByteArrayRegion(byteArray, 0, 16, (const jbyte *)&(in6->sin6_addr)); isSupported = true; } else { ALOGE("Unable to allocate byte array for IPv6 address."); } } break; default: ALOGE("Invalid ss_family found: %d", agps_status->addr.ss_family); break; } } else if (status_size >= sizeof(AGpsStatus_v2)) { // for back-compatibility reasons we check in v2 that the data structure size is greater or // equal to the declared size in gps.h uint32_t ipaddr = agps_status->ipaddr; byteArray = convert_to_ipv4(ipaddr, false /* net_order */); if (ipaddr == INADDR_NONE || byteArray != NULL) { isSupported = true; } } else if (status_size >= sizeof(AGpsStatus_v1)) { // because we have to check for >= with regards to v2, we also need to relax the check here // and only make sure that the size is at least what we expect isSupported = true; } else { ALOGE("Invalid size of AGpsStatus found: %d.", status_size); } if (isSupported) { env->CallVoidMethod(mCallbacksObj, method_reportAGpsStatus, agps_status->type, agps_status->status, byteArray); uint32_t ipaddr; // ipaddr field was not included in original AGpsStatus if (agps_status->size >= sizeof(AGpsStatus)) ipaddr = agps_status->ipaddr; else ipaddr = 0xFFFFFFFF; env->CallVoidMethod(mCallbacksObj, method_reportAGpsStatus, agps_status->type, agps_status->status, ipaddr); checkAndClearExceptionFromCallback(env, __FUNCTION__); } else { ALOGD("Skipping calling method_reportAGpsStatus."); } if (byteArray) { env->DeleteLocalRef(byteArray); } } AGpsCallbacks sAGpsCallbacks = { Loading Loading @@ -339,7 +420,7 @@ static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V"); method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V"); method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V"); method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(III)V"); method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II[B)V"); method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V"); method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V"); method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V"); Loading Loading @@ -610,7 +691,8 @@ static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, j env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT); } static void android_location_GpsLocationProvider_agps_data_conn_open(JNIEnv* env, jobject obj, jstring apn) static void android_location_GpsLocationProvider_agps_data_conn_open( JNIEnv* env, jobject obj, jstring apn, jint apnIpType) { if (!sAGpsInterface) { ALOGE("no AGPS interface in agps_data_conn_open"); Loading @@ -620,8 +702,18 @@ static void android_location_GpsLocationProvider_agps_data_conn_open(JNIEnv* env jniThrowException(env, "java/lang/IllegalArgumentException", NULL); return; } const char *apnStr = env->GetStringUTFChars(apn, NULL); size_t interface_size = sAGpsInterface->size; if (interface_size == sizeof(AGpsInterface_v2)) { sAGpsInterface->data_conn_open_with_apn_ip_type(apnStr, apnIpType); } else if (interface_size == sizeof(AGpsInterface_v1)) { sAGpsInterface->data_conn_open(apnStr); } else { ALOGE("Invalid size of AGpsInterface found: %d.", interface_size); } env->ReleaseStringUTFChars(apn, apnStr); } Loading Loading @@ -775,7 +867,7 @@ static JNINativeMethod sMethods[] = { {"native_inject_location", "(DDF)V", (void*)android_location_GpsLocationProvider_inject_location}, {"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra}, {"native_inject_xtra_data", "([BI)V", (void*)android_location_GpsLocationProvider_inject_xtra_data}, {"native_agps_data_conn_open", "(Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_agps_data_conn_open}, {"native_agps_data_conn_open", "(Ljava/lang/String;I)V", (void*)android_location_GpsLocationProvider_agps_data_conn_open}, {"native_agps_data_conn_closed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_closed}, {"native_agps_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_failed}, {"native_agps_set_id","(ILjava/lang/String;)V",(void*)android_location_GpsLocationProvider_agps_set_id}, Loading Loading
services/core/java/com/android/server/location/GpsLocationProvider.java +121 −35 Original line number Diff line number Diff line Loading @@ -83,6 +83,8 @@ import java.util.ArrayList; import java.util.Date; import java.util.Map.Entry; import java.util.Properties; import java.net.InetAddress; import java.net.UnknownHostException; /** * A GPS implementation of LocationProvider used by LocationManager. Loading Loading @@ -158,6 +160,12 @@ public class GpsLocationProvider implements LocationProviderInterface { private static final int AGPS_TYPE_SUPL = 1; private static final int AGPS_TYPE_C2K = 2; // these must match the definitions in gps.h private static final int APN_INVALID = 0; private static final int APN_IPV4 = 1; private static final int APN_IPV6 = 2; private static final int APN_IPV4V6 = 3; // for mAGpsDataConnectionState private static final int AGPS_DATA_CONNECTION_CLOSED = 0; private static final int AGPS_DATA_CONNECTION_OPENING = 1; Loading Loading @@ -312,8 +320,9 @@ public class GpsLocationProvider implements LocationProviderInterface { private Handler mHandler; private String mAGpsApn; private int mApnIpType; private int mAGpsDataConnectionState; private int mAGpsDataConnectionIpAddr; private InetAddress mAGpsDataConnectionIpAddr; private final ConnectivityManager mConnMgr; private final GpsNetInitiatedHandler mNIHandler; Loading Loading @@ -595,28 +604,28 @@ public class GpsLocationProvider implements LocationProviderInterface { if (info != null && info.getType() == ConnectivityManager.TYPE_MOBILE_SUPL && mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) { String apnName = info.getExtraInfo(); if (mNetworkAvailable) { String apnName = info.getExtraInfo(); if (apnName == null) { /* Assign a dummy value in the case of C2K as otherwise we will have a runtime exception in the following call to native_agps_data_conn_open*/ apnName = "dummy-apn"; } mAGpsApn = apnName; if (DEBUG) Log.d(TAG, "mAGpsDataConnectionIpAddr " + mAGpsDataConnectionIpAddr); if (mAGpsDataConnectionIpAddr != 0xffffffff) { boolean route_result; if (DEBUG) Log.d(TAG, "call requestRouteToHost"); route_result = mConnMgr.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_SUPL, mAGpsDataConnectionIpAddr); if (route_result == false) Log.d(TAG, "call requestRouteToHost failed"); mApnIpType = getApnIpType(apnName); setRouting(); if (DEBUG) { String message = String.format( "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s", mAGpsApn, mApnIpType); Log.d(TAG, message); } if (DEBUG) Log.d(TAG, "call native_agps_data_conn_open"); native_agps_data_conn_open(apnName); native_agps_data_conn_open(mAGpsApn, mApnIpType); mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; } else { if (DEBUG) Log.d(TAG, "call native_agps_data_conn_failed"); Log.e(TAG, "call native_agps_data_conn_failed, info: " + info); mAGpsApn = null; mApnIpType = APN_INVALID; mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; native_agps_data_conn_failed(); } Loading Loading @@ -1324,7 +1333,7 @@ public class GpsLocationProvider implements LocationProviderInterface { /** * called from native code to update AGPS status */ private void reportAGpsStatus(int type, int status, int ipaddr) { private void reportAGpsStatus(int type, int status, byte[] ipaddr) { switch (status) { case GPS_REQUEST_AGPS_DATA_CONN: if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN"); Loading @@ -1333,20 +1342,20 @@ public class GpsLocationProvider implements LocationProviderInterface { mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING; int result = mConnMgr.startUsingNetworkFeature( ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL); mAGpsDataConnectionIpAddr = ipaddr; if (ipaddr != null) { try { mAGpsDataConnectionIpAddr = InetAddress.getByAddress(ipaddr); } catch (UnknownHostException e) { Log.e(TAG, "Bad IP Address: " + ipaddr, e); mAGpsDataConnectionIpAddr = null; } } if (result == PhoneConstants.APN_ALREADY_ACTIVE) { if (DEBUG) Log.d(TAG, "PhoneConstants.APN_ALREADY_ACTIVE"); if (mAGpsApn != null) { Log.d(TAG, "mAGpsDataConnectionIpAddr " + mAGpsDataConnectionIpAddr); if (mAGpsDataConnectionIpAddr != 0xffffffff) { boolean route_result; if (DEBUG) Log.d(TAG, "call requestRouteToHost"); route_result = mConnMgr.requestRouteToHost( ConnectivityManager.TYPE_MOBILE_SUPL, mAGpsDataConnectionIpAddr); if (route_result == false) Log.d(TAG, "call requestRouteToHost failed"); } native_agps_data_conn_open(mAGpsApn); setRouting(); native_agps_data_conn_open(mAGpsApn, mApnIpType); mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; } else { Log.e(TAG, "mAGpsApn not set when receiving PhoneConstants.APN_ALREADY_ACTIVE"); Loading @@ -1370,6 +1379,7 @@ public class GpsLocationProvider implements LocationProviderInterface { ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL); native_agps_data_conn_closed(); mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; mAGpsDataConnectionIpAddr = null; } break; case GPS_AGPS_DATA_CONNECTED: Loading Loading @@ -1821,21 +1831,97 @@ public class GpsLocationProvider implements LocationProviderInterface { private String getSelectedApn() { Uri uri = Uri.parse("content://telephony/carriers/preferapn"); String apn = null; Cursor cursor = null; try { cursor = mContext.getContentResolver().query( uri, new String[] { "apn" }, null /* selection */, null /* selectionArgs */, Carriers.DEFAULT_SORT_ORDER); if (cursor != null && cursor.moveToFirst()) { return cursor.getString(0); } else { Log.e(TAG, "No APN found to select."); } } catch (Exception e) { Log.e(TAG, "Error encountered on selectiong the APN.", e); } finally { if (cursor != null) { cursor.close(); } } Cursor cursor = mContext.getContentResolver().query(uri, new String[] {"apn"}, null, null, Carriers.DEFAULT_SORT_ORDER); return null; } if (null != cursor) { private int getApnIpType(String apn) { if (apn == null) { return APN_INVALID; } // look for cached data to use if (apn.equals(mAGpsApn) && mApnIpType != APN_INVALID) { return mApnIpType; } String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn); Cursor cursor = null; try { if (cursor.moveToFirst()) { apn = cursor.getString(0); cursor = mContext.getContentResolver().query( Carriers.CONTENT_URI, new String[] { Carriers.PROTOCOL }, selection, null, Carriers.DEFAULT_SORT_ORDER); if (null != cursor && cursor.moveToFirst()) { return translateToApnIpType(cursor.getString(0), apn); } else { Log.e(TAG, "No entry found in query for APN: " + apn); } } catch (Exception e) { Log.e(TAG, "Error encountered on APN query for: " + apn, e); } finally { if (cursor != null) { cursor.close(); } } return apn; return APN_INVALID; } private int translateToApnIpType(String ipProtocol, String apn) { if ("IP".equals(ipProtocol)) { return APN_IPV4; } if ("IPV6".equals(ipProtocol)) { return APN_IPV6; } if ("IPV4V6".equals(ipProtocol)) { return APN_IPV4V6; } // we hit the default case so the ipProtocol is not recognized String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn); Log.e(TAG, message); return APN_INVALID; } private void setRouting() { if (mAGpsDataConnectionIpAddr == null) { return; } boolean result = mConnMgr.requestRouteToHostAddress( ConnectivityManager.TYPE_MOBILE_SUPL, mAGpsDataConnectionIpAddr); if (!result) { Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr); } else if (DEBUG) { Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr); } } @Override Loading Loading @@ -1897,7 +1983,7 @@ public class GpsLocationProvider implements LocationProviderInterface { private native String native_get_internal_state(); // AGPS Support private native void native_agps_data_conn_open(String apn); private native void native_agps_data_conn_open(String apn, int apnIpType); private native void native_agps_data_conn_closed(); private native void native_agps_data_conn_failed(); private native void native_agps_ni_message(byte [] msg, int length); Loading
services/core/jni/com_android_server_location_GpsLocationProvider.cpp +105 −13 Original line number Diff line number Diff line Loading @@ -30,6 +30,8 @@ #include <string.h> #include <pthread.h> #include <linux/in.h> #include <linux/in6.h> static jobject mCallbacksObj = NULL; Loading Loading @@ -168,19 +170,98 @@ GpsXtraCallbacks sGpsXtraCallbacks = { create_thread_callback, }; static jbyteArray convert_to_ipv4(uint32_t ip, bool net_order) { if (INADDR_NONE == ip) { return NULL; } JNIEnv* env = AndroidRuntime::getJNIEnv(); jbyteArray byteArray = env->NewByteArray(4); if (byteArray == NULL) { ALOGE("Unable to allocate byte array for IPv4 address"); return NULL; } jbyte ipv4[4]; if (net_order) { memcpy(ipv4, &ip, sizeof(ipv4)); } else { //endianess transparent conversion from int to char[] ipv4[0] = (jbyte) (ip & 0xFF); ipv4[1] = (jbyte)((ip>>8) & 0xFF); ipv4[2] = (jbyte)((ip>>16) & 0xFF); ipv4[3] = (jbyte) (ip>>24); } env->SetByteArrayRegion(byteArray, 0, 4, (const jbyte*) ipv4); return byteArray; } static void agps_status_callback(AGpsStatus* agps_status) { JNIEnv* env = AndroidRuntime::getJNIEnv(); jbyteArray byteArray = NULL; bool isSupported = false; size_t status_size = agps_status->size; if (status_size == sizeof(AGpsStatus_v3)) { switch (agps_status->addr.ss_family) { case AF_INET: { struct sockaddr_in *in = (struct sockaddr_in*)&(agps_status->addr); uint32_t *pAddr = (uint32_t*)&(in->sin_addr); byteArray = convert_to_ipv4(*pAddr, true /* net_order */); if (byteArray != NULL) { isSupported = true; } } break; case AF_INET6: { struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&(agps_status->addr); byteArray = env->NewByteArray(16); if (byteArray != NULL) { env->SetByteArrayRegion(byteArray, 0, 16, (const jbyte *)&(in6->sin6_addr)); isSupported = true; } else { ALOGE("Unable to allocate byte array for IPv6 address."); } } break; default: ALOGE("Invalid ss_family found: %d", agps_status->addr.ss_family); break; } } else if (status_size >= sizeof(AGpsStatus_v2)) { // for back-compatibility reasons we check in v2 that the data structure size is greater or // equal to the declared size in gps.h uint32_t ipaddr = agps_status->ipaddr; byteArray = convert_to_ipv4(ipaddr, false /* net_order */); if (ipaddr == INADDR_NONE || byteArray != NULL) { isSupported = true; } } else if (status_size >= sizeof(AGpsStatus_v1)) { // because we have to check for >= with regards to v2, we also need to relax the check here // and only make sure that the size is at least what we expect isSupported = true; } else { ALOGE("Invalid size of AGpsStatus found: %d.", status_size); } if (isSupported) { env->CallVoidMethod(mCallbacksObj, method_reportAGpsStatus, agps_status->type, agps_status->status, byteArray); uint32_t ipaddr; // ipaddr field was not included in original AGpsStatus if (agps_status->size >= sizeof(AGpsStatus)) ipaddr = agps_status->ipaddr; else ipaddr = 0xFFFFFFFF; env->CallVoidMethod(mCallbacksObj, method_reportAGpsStatus, agps_status->type, agps_status->status, ipaddr); checkAndClearExceptionFromCallback(env, __FUNCTION__); } else { ALOGD("Skipping calling method_reportAGpsStatus."); } if (byteArray) { env->DeleteLocalRef(byteArray); } } AGpsCallbacks sAGpsCallbacks = { Loading Loading @@ -339,7 +420,7 @@ static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V"); method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V"); method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V"); method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(III)V"); method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II[B)V"); method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V"); method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V"); method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V"); Loading Loading @@ -610,7 +691,8 @@ static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, j env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT); } static void android_location_GpsLocationProvider_agps_data_conn_open(JNIEnv* env, jobject obj, jstring apn) static void android_location_GpsLocationProvider_agps_data_conn_open( JNIEnv* env, jobject obj, jstring apn, jint apnIpType) { if (!sAGpsInterface) { ALOGE("no AGPS interface in agps_data_conn_open"); Loading @@ -620,8 +702,18 @@ static void android_location_GpsLocationProvider_agps_data_conn_open(JNIEnv* env jniThrowException(env, "java/lang/IllegalArgumentException", NULL); return; } const char *apnStr = env->GetStringUTFChars(apn, NULL); size_t interface_size = sAGpsInterface->size; if (interface_size == sizeof(AGpsInterface_v2)) { sAGpsInterface->data_conn_open_with_apn_ip_type(apnStr, apnIpType); } else if (interface_size == sizeof(AGpsInterface_v1)) { sAGpsInterface->data_conn_open(apnStr); } else { ALOGE("Invalid size of AGpsInterface found: %d.", interface_size); } env->ReleaseStringUTFChars(apn, apnStr); } Loading Loading @@ -775,7 +867,7 @@ static JNINativeMethod sMethods[] = { {"native_inject_location", "(DDF)V", (void*)android_location_GpsLocationProvider_inject_location}, {"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra}, {"native_inject_xtra_data", "([BI)V", (void*)android_location_GpsLocationProvider_inject_xtra_data}, {"native_agps_data_conn_open", "(Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_agps_data_conn_open}, {"native_agps_data_conn_open", "(Ljava/lang/String;I)V", (void*)android_location_GpsLocationProvider_agps_data_conn_open}, {"native_agps_data_conn_closed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_closed}, {"native_agps_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_failed}, {"native_agps_set_id","(ILjava/lang/String;)V",(void*)android_location_GpsLocationProvider_agps_set_id}, Loading