summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java177
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp73
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)},