diff options
| -rw-r--r-- | services/core/java/com/android/server/location/GnssLocationProvider.java | 177 | ||||
| -rw-r--r-- | services/core/jni/com_android_server_location_GnssLocationProvider.cpp | 73 |
2 files changed, 226 insertions, 24 deletions
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 3e43d8ed918d..9d2a8e28a3a0 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -16,6 +16,7 @@ package com.android.server.location; +import android.annotation.Nullable; import android.app.AlarmManager; import android.app.AppOpsManager; import android.app.PendingIntent; @@ -28,11 +29,11 @@ import android.hardware.location.GeofenceHardware; import android.hardware.location.GeofenceHardwareImpl; import android.location.Criteria; import android.location.FusedBatchOptions; +import android.location.GnssMeasurementsEvent; +import android.location.GnssNavigationMessage; import android.location.GnssStatus; import android.location.IGnssStatusListener; import android.location.IGnssStatusProvider; -import android.location.GnssMeasurementsEvent; -import android.location.GnssNavigationMessage; import android.location.IGpsGeofenceHardware; import android.location.ILocationManager; import android.location.INetInitiatedListener; @@ -48,16 +49,16 @@ import android.net.NetworkInfo; import android.net.NetworkRequest; import android.net.Uri; import android.os.AsyncTask; -import android.os.PowerManager.ServiceType; -import android.os.PowerSaveState; import android.os.BatteryStats; import android.os.Binder; import android.os.Bundle; -import android.os.PersistableBundle; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.PersistableBundle; import android.os.PowerManager; +import android.os.PowerManager.ServiceType; +import android.os.PowerSaveState; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; @@ -68,25 +69,21 @@ import android.os.WorkSource.WorkChain; import android.provider.Settings; import android.provider.Telephony.Carriers; import android.provider.Telephony.Sms.Intents; +import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.TelephonyManager; -import android.telephony.CarrierConfigManager; import android.telephony.gsm.GsmCellLocation; import android.text.TextUtils; import android.util.Log; import android.util.NtpTrustedTime; - import com.android.internal.app.IAppOpsService; import com.android.internal.app.IBatteryStats; -import com.android.internal.location.gnssmetrics.GnssMetrics; import com.android.internal.location.GpsNetInitiatedHandler; import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification; import com.android.internal.location.ProviderProperties; import com.android.internal.location.ProviderRequest; - -import libcore.io.IoUtils; - +import com.android.internal.location.gnssmetrics.GnssMetrics; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; @@ -97,11 +94,13 @@ import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Map.Entry; import java.util.Properties; -import java.util.Map; -import java.util.HashMap; + +import libcore.io.IoUtils; /** * A GNSS implementation of LocationProvider used by LocationManager. @@ -215,6 +214,7 @@ public class GnssLocationProvider implements LocationProviderInterface { private static final int INITIALIZE_HANDLER = 13; private static final int REQUEST_SUPL_CONNECTION = 14; private static final int RELEASE_SUPL_CONNECTION = 15; + private static final int REQUEST_LOCATION = 16; // Request setid private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1; @@ -248,6 +248,13 @@ public class GnssLocationProvider implements LocationProviderInterface { private static final int TCP_MIN_PORT = 0; private static final int TCP_MAX_PORT = 0xffff; + // 10 seconds. + private static final long LOCATION_TIME_FRESHNESS_THESHOLD_MILLIS = 10 * 1000; + // 1 second, or 1 Hz frequency. + private static final long LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS = 1000; + // 30 seconds. + private static final long LOCATION_UPDATE_DURATION_MILLIS = 30 * 1000; + /** simpler wrapper for ProviderRequest + Worksource */ private static class GpsRequest { public ProviderRequest request; @@ -409,6 +416,8 @@ public class GnssLocationProvider implements LocationProviderInterface { private final GnssStatusListenerHelper mListenerHelper; private final GnssMeasurementsProvider mGnssMeasurementsProvider; private final GnssNavigationMessageProvider mGnssNavigationMessageProvider; + private final FusedLocationListener mFusedLocationListener = new FusedLocationListener(); + private static int sNumFusedLocationUpdatesRequests = 0; // Handler for processing events private Handler mHandler; @@ -1074,6 +1083,89 @@ public class GnssLocationProvider implements LocationProviderInterface { }); } + private void handleRequestLocation(boolean independentFromGnss) { + if (isRequestLocationRateLimited()) { + if (DEBUG) { + Log.d(TAG, "RequestLocation is denied due to too frequent requests."); + } + return; + } + + LocationManager locationManager = (LocationManager) mContext.getSystemService( + Context.LOCATION_SERVICE); + + if (independentFromGnss) { + // For fast GNSS TTFF + Location networkLocation = getLastFreshLocation(locationManager, + LocationManager.NETWORK_PROVIDER); + if (networkLocation != null) { + handleUpdateLocation(networkLocation); + return; + } + locationManager.requestSingleUpdate(LocationManager.NETWORK_PROVIDER, + new NetworkLocationListener(), + mHandler.getLooper()); + } else { + // For Device-Based Hybrid (E911) + locationManager.requestLocationUpdates(LocationManager.FUSED_PROVIDER, + LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS, /*minDistance=*/ 0, + mFusedLocationListener, mHandler.getLooper()); + sNumFusedLocationUpdatesRequests++; + mHandler.postDelayed(() -> { + if (--sNumFusedLocationUpdatesRequests == 0) { + locationManager.removeUpdates(mFusedLocationListener); + } + }, LOCATION_UPDATE_DURATION_MILLIS); + } + } + + private void injectBestLocation(Location location) { + int gnssLocationFlags = LOCATION_HAS_LAT_LONG | + (location.hasAltitude() ? LOCATION_HAS_ALTITUDE : 0) | + (location.hasSpeed() ? LOCATION_HAS_SPEED : 0) | + (location.hasBearing() ? LOCATION_HAS_BEARING : 0) | + (location.hasAccuracy() ? LOCATION_HAS_HORIZONTAL_ACCURACY : 0) | + (location.hasVerticalAccuracy() ? LOCATION_HAS_VERTICAL_ACCURACY : 0) | + (location.hasSpeedAccuracy() ? LOCATION_HAS_SPEED_ACCURACY : 0) | + (location.hasBearingAccuracy() ? LOCATION_HAS_BEARING_ACCURACY : 0); + + double latitudeDegrees = location.getLatitude(); + double longitudeDegrees = location.getLongitude(); + double altitudeMeters = location.getAltitude(); + float speedMetersPerSec = location.getSpeed(); + float bearingDegrees = location.getBearing(); + float horizontalAccuracyMeters = location.getAccuracy(); + float verticalAccuracyMeters = location.getVerticalAccuracyMeters(); + float speedAccuracyMetersPerSecond = location.getSpeedAccuracyMetersPerSecond(); + float bearingAccuracyDegrees = location.getBearingAccuracyDegrees(); + long timestamp = location.getTime(); + native_inject_best_location(gnssLocationFlags, latitudeDegrees, longitudeDegrees, + altitudeMeters, speedMetersPerSec, bearingDegrees, horizontalAccuracyMeters, + verticalAccuracyMeters, speedAccuracyMetersPerSecond, bearingAccuracyDegrees, + timestamp); + } + + /** + * Get the last fresh location. + * + * Return null if the last location is not available or not fresh. + */ + private @Nullable + Location getLastFreshLocation(LocationManager locationManager, String provider) { + Location location = locationManager.getLastKnownLocation(provider); + if (location != null && System.currentTimeMillis() - location.getTime() + < LOCATION_TIME_FRESHNESS_THESHOLD_MILLIS) { + return location; + } + return null; + } + + /** Returns true if the location request is too frequent. */ + private boolean isRequestLocationRateLimited() { + // TODO(b/73198123): implement exponential backoff. + return false; + } + private void handleDownloadXtraData() { if (!mSupportsXtra) { // native code reports xtra not supported, don't try @@ -2271,6 +2363,16 @@ public class GnssLocationProvider implements LocationProviderInterface { } /** + * Called from native code to request location info. + */ + private void requestLocation(boolean independentFromGnss) { + if (DEBUG) { + Log.d(TAG, "requestLocation. independentFromGnss: " + independentFromGnss); + } + sendMessage(REQUEST_LOCATION, 0, independentFromGnss); + } + + /** * Called from native code to request utc time info */ private void requestUtcTime() { @@ -2281,7 +2383,6 @@ public class GnssLocationProvider implements LocationProviderInterface { /** * Called from native code to request reference location info */ - private void requestRefLocation() { TelephonyManager phone = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); @@ -2357,6 +2458,9 @@ public class GnssLocationProvider implements LocationProviderInterface { case INJECT_NTP_TIME: handleInjectNtpTime(); break; + case REQUEST_LOCATION: + handleRequestLocation((boolean) msg.obj); + break; case DOWNLOAD_XTRA_DATA: handleDownloadXtraData(); break; @@ -2482,15 +2586,7 @@ public class GnssLocationProvider implements LocationProviderInterface { } } - private final class NetworkLocationListener implements LocationListener { - @Override - public void onLocationChanged(Location location) { - // this callback happens on mHandler looper - if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) { - handleUpdateLocation(location); - } - } - + private abstract class LocationChangeListener implements LocationListener { @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @@ -2504,6 +2600,26 @@ public class GnssLocationProvider implements LocationProviderInterface { } } + private final class NetworkLocationListener extends LocationChangeListener { + @Override + public void onLocationChanged(Location location) { + // this callback happens on mHandler looper + if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) { + handleUpdateLocation(location); + } + } + } + + private final class FusedLocationListener extends LocationChangeListener { + @Override + public void onLocationChanged(Location location) { + if (LocationManager.FUSED_PROVIDER.equals(location.getProvider())) { + Log.d(TAG, "fused location listener: " + location); + injectBestLocation(location); + } + } + } + private String getSelectedApn() { Uri uri = Uri.parse("content://telephony/carriers/preferapn"); Cursor cursor = null; @@ -2668,6 +2784,8 @@ public class GnssLocationProvider implements LocationProviderInterface { return "RELEASE_SUPL_CONNECTION"; case INJECT_NTP_TIME: return "INJECT_NTP_TIME"; + case REQUEST_LOCATION: + return "REQUEST_LOCATION"; case DOWNLOAD_XTRA_DATA: return "DOWNLOAD_XTRA_DATA"; case INJECT_NTP_TIME_FINISHED: @@ -2788,6 +2906,19 @@ public class GnssLocationProvider implements LocationProviderInterface { private native int native_read_nmea(byte[] buffer, int bufferSize); + private native void native_inject_best_location( + int gnssLocationFlags, + double latitudeDegrees, + double longitudeDegrees, + double altitudeMeters, + float speedMetersPerSec, + float bearingDegrees, + float horizontalAccuracyMeters, + float verticalAccuracyMeters, + float speedAccuracyMetersPerSecond, + float bearingAccuracyDegrees, + long timestamp); + private native void native_inject_location(double latitude, double longitude, float accuracy); // XTRA Support diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index 8fd5be2a45ff..c2771e4b931f 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -51,6 +51,7 @@ static jmethodID method_setGnssYearOfHardware; static jmethodID method_setGnssHardwareModelName; static jmethodID method_xtraDownloadRequest; static jmethodID method_reportNiNotification; +static jmethodID method_requestLocation; static jmethodID method_requestRefLocation; static jmethodID method_requestSetID; static jmethodID method_requestUtcTime; @@ -346,6 +347,34 @@ static jobject translateLocation(JNIEnv* env, const GnssLocation& location) { return object.get(); } +static GnssLocation createGnssLocation( + jint gnssLocationFlags, + jdouble latitudeDegrees, + jdouble longitudeDegrees, + jdouble altitudeMeters, + jfloat speedMetersPerSec, + jfloat bearingDegrees, + jfloat horizontalAccuracyMeters, + jfloat verticalAccuracyMeters, + jfloat speedAccuracyMetersPerSecond, + jfloat bearingAccuracyDegrees, + jlong timestamp) { + GnssLocation location; + location.gnssLocationFlags = static_cast<uint16_t>(gnssLocationFlags); + location.latitudeDegrees = static_cast<double>(latitudeDegrees); + location.longitudeDegrees = static_cast<double>(longitudeDegrees); + location.altitudeMeters = static_cast<double>(altitudeMeters); + location.speedMetersPerSec = static_cast<float>(speedMetersPerSec); + location.bearingDegrees = static_cast<float>(bearingDegrees); + location.horizontalAccuracyMeters = static_cast<float>(horizontalAccuracyMeters); + location.verticalAccuracyMeters = static_cast<float>(verticalAccuracyMeters); + location.speedAccuracyMetersPerSecond = static_cast<float>(speedAccuracyMetersPerSecond); + location.bearingAccuracyDegrees = static_cast<float>(bearingAccuracyDegrees); + location.timestamp = static_cast<uint64_t>(timestamp); + + return location; +} + /* * GnssCallback class implements the callback methods for IGnss interface. */ @@ -474,7 +503,9 @@ Return<void> GnssCallback::gnssRequestTimeCb() { } Return<void> GnssCallback::gnssRequestLocationCb(const bool independentFromGnss) { - // TODO(b/72405645): call into java implementation + JNIEnv* env = getJniEnv(); + env->CallVoidMethod(mCallbacksObj, method_requestLocation, boolToJbool(independentFromGnss)); + checkAndClearExceptionFromCallback(env, __FUNCTION__); return Void(); } @@ -1042,6 +1073,7 @@ static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V"); method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification", "(IIIIILjava/lang/String;Ljava/lang/String;II)V"); + method_requestLocation = env->GetMethodID(clazz, "requestLocation", "(Z)V"); method_requestRefLocation = env->GetMethodID(clazz, "requestRefLocation", "()V"); method_requestSetID = env->GetMethodID(clazz, "requestSetID", "(I)V"); method_requestUtcTime = env->GetMethodID(clazz, "requestUtcTime", "()V"); @@ -1441,6 +1473,42 @@ static void android_location_GnssLocationProvider_inject_time(JNIEnv* /* env */, } } +static void android_location_GnssLocationProvider_inject_best_location( + JNIEnv*, + jobject, + jint gnssLocationFlags, + jdouble latitudeDegrees, + jdouble longitudeDegrees, + jdouble altitudeMeters, + jfloat speedMetersPerSec, + jfloat bearingDegrees, + jfloat horizontalAccuracyMeters, + jfloat verticalAccuracyMeters, + jfloat speedAccuracyMetersPerSecond, + jfloat bearingAccuracyDegrees, + jlong timestamp) { + if (gnssHal_V1_1 != nullptr) { + GnssLocation location = createGnssLocation( + gnssLocationFlags, + latitudeDegrees, + longitudeDegrees, + altitudeMeters, + speedMetersPerSec, + bearingDegrees, + horizontalAccuracyMeters, + verticalAccuracyMeters, + speedAccuracyMetersPerSecond, + bearingAccuracyDegrees, + timestamp); + auto result = gnssHal_V1_1->injectBestLocation(location); + if (!result.isOk() || !result) { + ALOGE("%s: Gnss injectBestLocation() failed.", __func__); + } + } else { + ALOGE("%s: injectBestLocation() is called but gnssHal_V1_1 is not available.", __func__); + } +} + static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env */, jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy) { if (gnssHal != nullptr) { @@ -1996,6 +2064,9 @@ static const JNINativeMethod sMethods[] = { android_location_GnssLocationProvider_read_nmea)}, {"native_inject_time", "(JJI)V", reinterpret_cast<void *>( android_location_GnssLocationProvider_inject_time)}, + {"native_inject_best_location", + "(IDDDFFFFFFJ)V", + reinterpret_cast<void *>(android_location_GnssLocationProvider_inject_best_location)}, {"native_inject_location", "(DDF)V", reinterpret_cast<void *>(android_location_GnssLocationProvider_inject_location)}, |