From a8e676b32697132588eca4bd7bb68291977cefe2 Mon Sep 17 00:00:00 2001 From: Soonil Nagarkar Date: Tue, 8 Dec 2020 18:47:08 -0800 Subject: [PATCH] Refactor Java GNSS HAL Extracts large parts of the GNSS HAL into a central GnssNative class, which can be faked for testing. This is a large step towards making all GNSS code unit testable, and allows for more modular HAL configurations. Begins to break up the GnssLocationProvider god object and pull functionality out into other classes. Changes include: -Making GnssCapabilities parcelable so it can be part of the API -Splitting out the NMEA listener from status listeners, which substantially reduces the burden of supported NMEA listeners as well as the amount of GNSS<->AP communication. -All GNSS listeners now respond properly to HAL restarts. -Partially extract out emergency call detection. Bug: 153129152 Test: manual Change-Id: Idee0d548f38c6adf921cd6c28b5d815bbd366f8a --- core/api/current.txt | 19 +- core/api/system-current.txt | 18 +- .../android/location/GnssCapabilities.aidl | 19 + .../android/location/GnssCapabilities.java | 794 +++++++-- .../android/location/IGnssNmeaListener.aidl | 25 + .../android/location/IGnssStatusListener.aidl | 1 - .../android/location/ILocationManager.aidl | 7 +- .../android/location/LocationManager.java | 245 ++- .../location/LocationManagerService.java | 89 +- .../gnss/GnssAntennaInfoProvider.java | 75 +- .../gnss/GnssCapabilitiesProvider.java | 127 -- .../location/gnss/GnssConfiguration.java | 28 +- ...ceProvider.java => GnssGeofenceProxy.java} | 103 +- .../location/gnss/GnssLocationProvider.java | 946 +++-------- .../location/gnss/GnssManagerService.java | 356 ++-- .../GnssMeasurementCorrectionsProvider.java | 151 -- .../gnss/GnssMeasurementsProvider.java | 103 +- .../server/location/gnss}/GnssMetrics.java | 30 +- .../server/location/gnss/GnssNative.java | 324 ---- .../gnss/GnssNavigationMessageProvider.java | 84 +- .../location/gnss/GnssNmeaProvider.java | 115 ++ .../gnss/GnssPowerIndicationProvider.java | 122 -- .../server/location/gnss/GnssPowerStats.java | 63 +- .../location/gnss/GnssStatusProvider.java | 80 +- .../server/location/gnss/hal/GnssNative.java | 1490 +++++++++++++++++ .../location/injector/EmergencyHelper.java | 29 + .../server/location/injector/Injector.java | 3 + .../injector/SystemEmergencyHelper.java | 94 ++ .../provider/LocationProviderManager.java | 8 + ...d_server_location_GnssLocationProvider.cpp | 464 +++-- .../gnss/GnssGeofenceProviderTest.java | 155 -- .../location/gnss/GnssPositionModeTest.java | 76 - .../location/gnss/GnssGeofenceProxyTest.java | 134 ++ .../location/gnss/GnssManagerServiceTest.java | 682 -------- .../server/location/gnss/hal/FakeGnssHal.java | 674 ++++++++ .../injector/FakeEmergencyHelper.java | 36 + .../location/injector/TestInjector.java | 7 + 37 files changed, 4441 insertions(+), 3335 deletions(-) create mode 100644 location/java/android/location/GnssCapabilities.aidl create mode 100644 location/java/android/location/IGnssNmeaListener.aidl delete mode 100644 services/core/java/com/android/server/location/gnss/GnssCapabilitiesProvider.java rename services/core/java/com/android/server/location/gnss/{GnssGeofenceProvider.java => GnssGeofenceProxy.java} (59%) delete mode 100644 services/core/java/com/android/server/location/gnss/GnssMeasurementCorrectionsProvider.java rename {location/java/com/android/internal/location/gnssmetrics => services/core/java/com/android/server/location/gnss}/GnssMetrics.java (96%) delete mode 100644 services/core/java/com/android/server/location/gnss/GnssNative.java create mode 100644 services/core/java/com/android/server/location/gnss/GnssNmeaProvider.java delete mode 100644 services/core/java/com/android/server/location/gnss/GnssPowerIndicationProvider.java create mode 100644 services/core/java/com/android/server/location/gnss/hal/GnssNative.java create mode 100644 services/core/java/com/android/server/location/injector/EmergencyHelper.java create mode 100644 services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java delete mode 100644 services/robotests/src/com/android/server/location/gnss/GnssGeofenceProviderTest.java delete mode 100644 services/robotests/src/com/android/server/location/gnss/GnssPositionModeTest.java create mode 100644 services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssGeofenceProxyTest.java delete mode 100644 services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java create mode 100644 services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java create mode 100644 services/tests/mockingservicestests/src/com/android/server/location/injector/FakeEmergencyHelper.java diff --git a/core/api/current.txt b/core/api/current.txt index 3ac71c53b1787..5c954e491aa97 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -18966,8 +18966,23 @@ package android.location { field @NonNull public static final android.os.Parcelable.Creator CREATOR; } - public final class GnssCapabilities { - method public boolean hasGnssAntennaInfo(); + public final class GnssCapabilities implements android.os.Parcelable { + method public int describeContents(); + method public boolean hasAntennaInfo(); + method @Deprecated public boolean hasGnssAntennaInfo(); + method public boolean hasMeasurements(); + method public boolean hasNavigationMessages(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public static final class GnssCapabilities.Builder { + ctor public GnssCapabilities.Builder(); + ctor public GnssCapabilities.Builder(@NonNull android.location.GnssCapabilities); + method @NonNull public android.location.GnssCapabilities build(); + method @NonNull public android.location.GnssCapabilities.Builder setHasAntennaInfo(boolean); + method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurements(boolean); + method @NonNull public android.location.GnssCapabilities.Builder setHasNavigationMessages(boolean); } public final class GnssClock implements android.os.Parcelable { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 567676f9caf89..5f97da928b14d 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -3938,19 +3938,29 @@ package android.location { method public void onLocationBatch(java.util.List); } - public final class GnssCapabilities { + public final class GnssCapabilities implements android.os.Parcelable { method public boolean hasGeofencing(); method public boolean hasLowPowerMode(); method public boolean hasMeasurementCorrections(); method public boolean hasMeasurementCorrectionsExcessPathLength(); method public boolean hasMeasurementCorrectionsLosSats(); - method public boolean hasMeasurementCorrectionsReflectingPane(); - method public boolean hasMeasurements(); - method public boolean hasNavMessages(); + method @Deprecated public boolean hasMeasurementCorrectionsReflectingPane(); + method public boolean hasMeasurementCorrectionsReflectingPlane(); + method @Deprecated public boolean hasNavMessages(); method @Deprecated public boolean hasSatelliteBlacklist(); method public boolean hasSatelliteBlocklist(); } + public static final class GnssCapabilities.Builder { + method @NonNull public android.location.GnssCapabilities.Builder setHasGeofencing(boolean); + method @NonNull public android.location.GnssCapabilities.Builder setHasLowPowerMode(boolean); + method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrections(boolean); + method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsExcessPathLength(boolean); + method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsLosSats(boolean); + method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsReflectingPlane(boolean); + method @NonNull public android.location.GnssCapabilities.Builder setHasSatelliteBlocklist(boolean); + } + public final class GnssMeasurementCorrections implements android.os.Parcelable { method public int describeContents(); method @FloatRange(from=-1000.0F, to=10000.0f) public double getAltitudeMeters(); diff --git a/location/java/android/location/GnssCapabilities.aidl b/location/java/android/location/GnssCapabilities.aidl new file mode 100644 index 0000000000000..bdf301483a5f2 --- /dev/null +++ b/location/java/android/location/GnssCapabilities.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2020, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.location; + +parcelable GnssCapabilities; \ No newline at end of file diff --git a/location/java/android/location/GnssCapabilities.java b/location/java/android/location/GnssCapabilities.java index bbb5bb8fa3a76..89a3bd57519ef 100644 --- a/location/java/android/location/GnssCapabilities.java +++ b/location/java/android/location/GnssCapabilities.java @@ -16,121 +16,207 @@ package android.location; +import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; +import java.util.concurrent.Executor; /** - * A container of supported GNSS chipset capabilities. + * GNSS chipset capabilities. */ -public final class GnssCapabilities { - /** - * Bit mask indicating GNSS chipset supports low power mode. - * @hide - */ - public static final long LOW_POWER_MODE = 1L << 0; +public final class GnssCapabilities implements Parcelable { - /** - * Bit mask indicating GNSS chipset supports blocklisting satellites. - * @hide - */ - public static final long SATELLITE_BLOCKLIST = 1L << 1; - - /** - * Bit mask indicating GNSS chipset supports geofencing. - * @hide - */ - public static final long GEOFENCING = 1L << 2; - - /** - * Bit mask indicating GNSS chipset supports measurements. - * @hide - */ - public static final long MEASUREMENTS = 1L << 3; - - /** - * Bit mask indicating GNSS chipset supports navigation messages. - * @hide - */ - public static final long NAV_MESSAGES = 1L << 4; - - /** - * Bit mask indicating GNSS chipset supports measurement corrections. - * @hide - */ - public static final long MEASUREMENT_CORRECTIONS = 1L << 5; - - /** - * Bit mask indicating GNSS chipset supports line-of-sight satellite identification - * measurement corrections. - * @hide - */ - public static final long MEASUREMENT_CORRECTIONS_LOS_SATS = 1L << 6; - - /** - * Bit mask indicating GNSS chipset supports per satellite excess-path-length - * measurement corrections. - * @hide - */ - public static final long MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH = 1L << 7; - - /** - * Bit mask indicating GNSS chipset supports reflecting planes measurement corrections. - * @hide - */ - public static final long MEASUREMENT_CORRECTIONS_REFLECTING_PLANE = 1L << 8; - - /** - * Bit mask indicating GNSS chipset supports GNSS antenna info. - * @hide - */ - public static final long ANTENNA_INFO = 1L << 9; + // IMPORTANT - must match the Capabilities enum in IGnssCallback.hal + /** @hide */ + public static final int TOP_HAL_CAPABILITY_SCHEDULING = 1; + /** @hide */ + public static final int TOP_HAL_CAPABILITY_MSB = 2; + /** @hide */ + public static final int TOP_HAL_CAPABILITY_MSA = 4; + /** @hide */ + public static final int TOP_HAL_CAPABILITY_SINGLE_SHOT = 8; + /** @hide */ + public static final int TOP_HAL_CAPABILITY_ON_DEMAND_TIME = 16; + /** @hide */ + public static final int TOP_HAL_CAPABILITY_GEOFENCING = 32; + /** @hide */ + public static final int TOP_HAL_CAPABILITY_MEASUREMENTS = 64; + /** @hide */ + public static final int TOP_HAL_CAPABILITY_NAV_MESSAGES = 128; + /** @hide */ + public static final int TOP_HAL_CAPABILITY_LOW_POWER_MODE = 256; + /** @hide */ + public static final int TOP_HAL_CAPABILITY_SATELLITE_BLOCKLIST = 512; + /** @hide */ + public static final int TOP_HAL_CAPABILITY_MEASUREMENT_CORRECTIONS = 1024; + /** @hide */ + public static final int TOP_HAL_CAPABILITY_ANTENNA_INFO = 2048; /** @hide */ - public static final long INVALID_CAPABILITIES = -1; + @IntDef(flag = true, prefix = {"TOP_HAL_CAPABILITY_"}, value = {TOP_HAL_CAPABILITY_SCHEDULING, + TOP_HAL_CAPABILITY_MSB, TOP_HAL_CAPABILITY_MSA, TOP_HAL_CAPABILITY_SINGLE_SHOT, + TOP_HAL_CAPABILITY_ON_DEMAND_TIME, TOP_HAL_CAPABILITY_GEOFENCING, + TOP_HAL_CAPABILITY_MEASUREMENTS, TOP_HAL_CAPABILITY_NAV_MESSAGES, + TOP_HAL_CAPABILITY_LOW_POWER_MODE, TOP_HAL_CAPABILITY_SATELLITE_BLOCKLIST, + TOP_HAL_CAPABILITY_MEASUREMENT_CORRECTIONS, TOP_HAL_CAPABILITY_ANTENNA_INFO}) + @Retention(RetentionPolicy.SOURCE) + public @interface TopHalCapabilityFlags {} - /** A bitmask of supported GNSS capabilities. */ - private final long mGnssCapabilities; + // IMPORTANT - must match the Capabilities enum in IMeasurementCorrectionsCallback.hal + /** @hide */ + public static final int SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_LOS_SATS = 1; + /** @hide */ + public static final int SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_EXCESS_PATH_LENGTH = 2; + /** @hide */ + public static final int SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_REFLECTING_PLANE = 4; /** @hide */ - public static GnssCapabilities of(long gnssCapabilities) { - return new GnssCapabilities(gnssCapabilities); - } + @IntDef(flag = true, prefix = {"SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_"}, value = { + SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_LOS_SATS, + SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_EXCESS_PATH_LENGTH, + SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_REFLECTING_PLANE}) + @Retention(RetentionPolicy.SOURCE) + public @interface SubHalMeasurementCorrectionsCapabilityFlags {} - private GnssCapabilities(long gnssCapabilities) { - mGnssCapabilities = gnssCapabilities; - } + // IMPORATANT - must match values in IGnssPowerIndicationCallback.aidl + /** @hide */ + public static final int SUB_HAL_POWER_CAPABILITY_TOTAL = 1; + /** @hide */ + public static final int SUB_HAL_POWER_CAPABILITY_SINGLEBAND_TRACKING = 2; + /** @hide */ + public static final int SUB_HAL_POWER_CAPABILITY_MULTIBAND_TRACKING = 4; + /** @hide */ + public static final int SUB_HAL_POWER_CAPABILITY_SINGLEBAND_ACQUISITION = 8; + /** @hide */ + public static final int SUB_HAL_POWER_CAPABILITY_MULTIBAND_ACQUISITION = 16; + /** @hide */ + public static final int SUB_HAL_POWER_CAPABILITY_OTHER_MODES = 32; + + /** @hide */ + @IntDef(flag = true, prefix = {"SUB_HAL_POWER_CAPABILITY_"}, value = { + SUB_HAL_POWER_CAPABILITY_TOTAL, SUB_HAL_POWER_CAPABILITY_SINGLEBAND_TRACKING, + SUB_HAL_POWER_CAPABILITY_MULTIBAND_TRACKING, + SUB_HAL_POWER_CAPABILITY_SINGLEBAND_ACQUISITION, + SUB_HAL_POWER_CAPABILITY_MULTIBAND_ACQUISITION, + SUB_HAL_POWER_CAPABILITY_OTHER_MODES}) + @Retention(RetentionPolicy.SOURCE) + public @interface SubHalPowerCapabilityFlags {} /** - * Returns {@code true} if GNSS chipset supports low power mode, {@code false} otherwise. + * Returns an empty GnssCapabilities object. * * @hide */ - @SystemApi - public boolean hasLowPowerMode() { - return hasCapability(LOW_POWER_MODE); + public static GnssCapabilities empty() { + return new GnssCapabilities(0, 0, 0); + } + + private final @TopHalCapabilityFlags int mTopFlags; + private final @SubHalMeasurementCorrectionsCapabilityFlags int mMeasurementCorrectionsFlags; + private final @SubHalPowerCapabilityFlags int mPowerFlags; + + private GnssCapabilities( + @TopHalCapabilityFlags int topFlags, + @SubHalMeasurementCorrectionsCapabilityFlags int measurementCorrectionsFlags, + @SubHalPowerCapabilityFlags int powerFlags) { + mTopFlags = topFlags; + mMeasurementCorrectionsFlags = measurementCorrectionsFlags; + mPowerFlags = powerFlags; } /** - * Returns {@code true} if GNSS chipset supports blocklisting satellites, {@code false} - * otherwise. + * Returns a new GnssCapabilities object with top hal values set from the given flags. * * @hide - * @deprecated use {@link #hasSatelliteBlocklist} instead. */ - @SystemApi - @Deprecated - public boolean hasSatelliteBlacklist() { - return hasCapability(SATELLITE_BLOCKLIST); + public GnssCapabilities withTopHalFlags(@TopHalCapabilityFlags int flags) { + if (mTopFlags == flags) { + return this; + } else { + return new GnssCapabilities(flags, mMeasurementCorrectionsFlags, mPowerFlags); + } } /** - * Returns {@code true} if GNSS chipset supports blocklisting satellites, {@code false} + * Returns a new GnssCapabilities object with gnss measurement corrections sub hal values set + * from the given flags. + * + * @hide + */ + public GnssCapabilities withSubHalMeasurementCorrectionsFlags( + @SubHalMeasurementCorrectionsCapabilityFlags int flags) { + if (mMeasurementCorrectionsFlags == flags) { + return this; + } else { + return new GnssCapabilities(mTopFlags, flags, mPowerFlags); + } + } + + /** + * Returns a new GnssCapabilities object with gnss measurement corrections sub hal values set + * from the given flags. + * + * @hide + */ + public GnssCapabilities withSubHalPowerFlags(@SubHalPowerCapabilityFlags int flags) { + if (mPowerFlags == flags) { + return this; + } else { + return new GnssCapabilities(mTopFlags, mMeasurementCorrectionsFlags, flags); + } + } + + /** + * Returns {@code true} if GNSS chipset supports scheduling, {@code false} otherwise. + * + * @hide + */ + public boolean hasScheduling() { + return (mTopFlags & TOP_HAL_CAPABILITY_SCHEDULING) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports Mobile Station Based assistance, {@code false} * otherwise. * * @hide */ - @SystemApi - public boolean hasSatelliteBlocklist() { - return hasCapability(SATELLITE_BLOCKLIST); + public boolean hasMsb() { + return (mTopFlags & TOP_HAL_CAPABILITY_MSB) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports Mobile Station Assisted assitance, + * {@code false} otherwise. + * + * @hide + */ + public boolean hasMsa() { + return (mTopFlags & TOP_HAL_CAPABILITY_MSA) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports single shot locating, {@code false} otherwise. + * + * @hide + */ + public boolean hasSingleShot() { + return (mTopFlags & TOP_HAL_CAPABILITY_SINGLE_SHOT) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports on demand time, {@code false} otherwise. + * + * @hide + */ + public boolean hasOnDemandTime() { + return (mTopFlags & TOP_HAL_CAPABILITY_ON_DEMAND_TIME) != 0; } /** @@ -140,27 +226,71 @@ public final class GnssCapabilities { */ @SystemApi public boolean hasGeofencing() { - return hasCapability(GEOFENCING); + return (mTopFlags & TOP_HAL_CAPABILITY_GEOFENCING) != 0; } /** * Returns {@code true} if GNSS chipset supports measurements, {@code false} otherwise. * - * @hide + * @see LocationManager#registerGnssMeasurementsCallback(Executor, GnssMeasurementsEvent.Callback) */ - @SystemApi public boolean hasMeasurements() { - return hasCapability(MEASUREMENTS); + return (mTopFlags & TOP_HAL_CAPABILITY_MEASUREMENTS) != 0; } /** * Returns {@code true} if GNSS chipset supports navigation messages, {@code false} otherwise. * + * @deprecated Use {@link #hasNavigationMessages()} instead. + * + * @hide + */ + @Deprecated + @SystemApi + public boolean hasNavMessages() { + return hasNavigationMessages(); + } + + /** + * Returns {@code true} if GNSS chipset supports navigation messages, {@code false} otherwise. + * + * @see LocationManager#registerGnssNavigationMessageCallback(Executor, GnssNavigationMessage.Callback) + */ + public boolean hasNavigationMessages() { + return (mTopFlags & TOP_HAL_CAPABILITY_NAV_MESSAGES) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports low power mode, {@code false} otherwise. + * * @hide */ @SystemApi - public boolean hasNavMessages() { - return hasCapability(NAV_MESSAGES); + public boolean hasLowPowerMode() { + return (mTopFlags & TOP_HAL_CAPABILITY_LOW_POWER_MODE) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports satellite blocklists, {@code false} otherwise. + * + * @deprecated Use {@link #hasSatelliteBlocklist} instead. + * + * @hide + */ + @SystemApi + @Deprecated + public boolean hasSatelliteBlacklist() { + return (mTopFlags & TOP_HAL_CAPABILITY_SATELLITE_BLOCKLIST) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports satellite blocklists, {@code false} otherwise. + * + * @hide + */ + @SystemApi + public boolean hasSatelliteBlocklist() { + return (mTopFlags & TOP_HAL_CAPABILITY_SATELLITE_BLOCKLIST) != 0; } /** @@ -171,7 +301,26 @@ public final class GnssCapabilities { */ @SystemApi public boolean hasMeasurementCorrections() { - return hasCapability(MEASUREMENT_CORRECTIONS); + return (mTopFlags & TOP_HAL_CAPABILITY_MEASUREMENT_CORRECTIONS) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports antenna info, {@code false} otherwise. + * + * @deprecated Use {@link #hasAntennaInfo()} instead. + */ + @Deprecated + public boolean hasGnssAntennaInfo() { + return hasAntennaInfo(); + } + + /** + * Returns {@code true} if GNSS chipset supports antenna info, {@code false} otherwise. + * + * @see LocationManager#registerAntennaInfoListener(Executor, GnssAntennaInfo.Listener) + */ + public boolean hasAntennaInfo() { + return (mTopFlags & TOP_HAL_CAPABILITY_ANTENNA_INFO) != 0; } /** @@ -182,7 +331,8 @@ public final class GnssCapabilities { */ @SystemApi public boolean hasMeasurementCorrectionsLosSats() { - return hasCapability(MEASUREMENT_CORRECTIONS_LOS_SATS); + return (mMeasurementCorrectionsFlags & SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_LOS_SATS) + != 0; } /** @@ -193,28 +343,468 @@ public final class GnssCapabilities { */ @SystemApi public boolean hasMeasurementCorrectionsExcessPathLength() { - return hasCapability(MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH); + return (mMeasurementCorrectionsFlags + & SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_EXCESS_PATH_LENGTH) != 0; } /** - * Returns {@code true} if GNSS chipset supports reflecting planes measurement corrections, + * Returns {@code true} if GNSS chipset supports reflecting plane measurement corrections, * {@code false} otherwise. * + * @deprecated Use {@link #hasMeasurementCorrectionsReflectingPlane()} instead. + * * @hide */ @SystemApi public boolean hasMeasurementCorrectionsReflectingPane() { - return hasCapability(MEASUREMENT_CORRECTIONS_REFLECTING_PLANE); + return hasMeasurementCorrectionsReflectingPlane(); } /** - * Returns {@code true} if GNSS chipset supports antenna info, {@code false} otherwise. + * Returns {@code true} if GNSS chipset supports reflecting plane measurement corrections, + * {@code false} otherwise. + * + * @hide */ - public boolean hasGnssAntennaInfo() { - return hasCapability(ANTENNA_INFO); + @SystemApi + public boolean hasMeasurementCorrectionsReflectingPlane() { + return (mMeasurementCorrectionsFlags + & SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_REFLECTING_PLANE) != 0; } - private boolean hasCapability(long capability) { - return (mGnssCapabilities & capability) == capability; + /** + * Returns {@code true} if GNSS chipset supports measuring power totals, {@code false} + * otherwise. + * + * @hide + */ + public boolean hasPowerTotal() { + return (mPowerFlags & SUB_HAL_POWER_CAPABILITY_TOTAL) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports measuring single-band tracking power, + * {@code false} otherwise. + * + * @hide + */ + public boolean hasPowerSinglebandTracking() { + return (mPowerFlags & SUB_HAL_POWER_CAPABILITY_SINGLEBAND_TRACKING) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports measuring multi-band tracking power, + * {@code false} otherwise. + * + * @hide + */ + public boolean hasPowerMultibandTracking() { + return (mPowerFlags & SUB_HAL_POWER_CAPABILITY_MULTIBAND_TRACKING) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports measuring single-band acquisition power, + * {@code false} otherwise. + * + * @hide + */ + public boolean hasPowerSinglebandAcquisition() { + return (mPowerFlags & SUB_HAL_POWER_CAPABILITY_SINGLEBAND_ACQUISITION) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports measuring multi-band acquisition power, + * {@code false} otherwise. + * + * @hide + */ + public boolean hasPowerMultibandAcquisition() { + return (mPowerFlags & SUB_HAL_POWER_CAPABILITY_MULTIBAND_ACQUISITION) != 0; + } + + /** + * Returns {@code true} if GNSS chipset supports measuring OEM defined mode power, {@code false} + * otherwise. + * + * @hide + */ + public boolean hasPowerOtherModes() { + return (mPowerFlags & SUB_HAL_POWER_CAPABILITY_OTHER_MODES) != 0; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof GnssCapabilities)) { + return false; + } + + GnssCapabilities that = (GnssCapabilities) o; + return mTopFlags == that.mTopFlags + && mMeasurementCorrectionsFlags == that.mMeasurementCorrectionsFlags + && mPowerFlags == that.mPowerFlags; + } + + @Override + public int hashCode() { + return Objects.hash(mTopFlags, mMeasurementCorrectionsFlags, mPowerFlags); + } + + public static final @NonNull Creator CREATOR = + new Creator() { + @Override + public GnssCapabilities createFromParcel(Parcel in) { + return new GnssCapabilities(in.readInt(), in.readInt(), in.readInt()); + } + + @Override + public GnssCapabilities[] newArray(int size) { + return new GnssCapabilities[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeInt(mTopFlags); + parcel.writeInt(mMeasurementCorrectionsFlags); + parcel.writeInt(mPowerFlags); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("["); + if (hasScheduling()) { + builder.append("SCHEDULING "); + } + if (hasMsb()) { + builder.append("MSB "); + } + if (hasMsa()) { + builder.append("MSA "); + } + if (hasSingleShot()) { + builder.append("SINGLE_SHOT "); + } + if (hasOnDemandTime()) { + builder.append("ON_DEMAND_TIME "); + } + if (hasGeofencing()) { + builder.append("GEOFENCING "); + } + if (hasMeasurementCorrections()) { + builder.append("MEASUREMENTS "); + } + if (hasNavigationMessages()) { + builder.append("NAVIGATION_MESSAGES "); + } + if (hasLowPowerMode()) { + builder.append("LOW_POWER_MODE "); + } + if (hasSatelliteBlocklist()) { + builder.append("SATELLITE_BLOCKLIST "); + } + if (hasMeasurementCorrections()) { + builder.append("MEASUREMENT_CORRECTIONS "); + } + if (hasAntennaInfo()) { + builder.append("ANTENNA_INFO "); + } + if (hasMeasurementCorrectionsLosSats()) { + builder.append("LOS_SATS "); + } + if (hasMeasurementCorrectionsExcessPathLength()) { + builder.append("EXCESS_PATH_LENGTH "); + } + if (hasMeasurementCorrectionsReflectingPlane()) { + builder.append("REFLECTING_PLANE "); + } + if (hasPowerTotal()) { + builder.append("TOTAL_POWER "); + } + if (hasPowerSinglebandTracking()) { + builder.append("SINGLEBAND_TRACKING_POWER "); + } + if (hasPowerMultibandTracking()) { + builder.append("MULTIBAND_TRACKING_POWER "); + } + if (hasPowerSinglebandAcquisition()) { + builder.append("SINGLEBAND_ACQUISITION_POWER "); + } + if (hasPowerMultibandAcquisition()) { + builder.append("MULTIBAND_ACQUISITION_POWER "); + } + if (hasPowerOtherModes()) { + builder.append("OTHER_MODES_POWER "); + } + if (builder.length() > 1) { + builder.setLength(builder.length() - 1); + } else { + builder.append("NONE"); + } + builder.append("]"); + return builder.toString(); + } + + /** + * Builder for GnssCapabilities. + */ + public static final class Builder { + + private @TopHalCapabilityFlags int mTopFlags; + private @SubHalMeasurementCorrectionsCapabilityFlags int mMeasurementCorrectionsFlags; + private @SubHalPowerCapabilityFlags int mPowerFlags; + + public Builder() { + mTopFlags = 0; + mMeasurementCorrectionsFlags = 0; + mPowerFlags = 0; + } + + public Builder(@NonNull GnssCapabilities capabilities) { + mTopFlags = capabilities.mTopFlags; + mMeasurementCorrectionsFlags = capabilities.mMeasurementCorrectionsFlags; + mPowerFlags = capabilities.mPowerFlags; + } + + /** + * Sets scheduling capability. + * + * @hide + */ + public @NonNull Builder setHasScheduling(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_SCHEDULING, capable); + return this; + } + + /** + * Sets Mobile Station Based capability. + * + * @hide + */ + public @NonNull Builder setHasMsb(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_MSB, capable); + return this; + } + + /** + * Sets Mobile Station Assisted capability. + * + * @hide + */ + public @NonNull Builder setHasMsa(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_MSA, capable); + return this; + } + + /** + * Sets single shot locating capability. + * + * @hide + */ + public @NonNull Builder setHasSingleShot(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_SINGLE_SHOT, capable); + return this; + } + + /** + * Sets on demand time capability. + * + * @hide + */ + public @NonNull Builder setHasOnDemandTime(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_ON_DEMAND_TIME, capable); + return this; + } + + /** + * Sets geofencing capability. + * + * @hide + */ + @SystemApi + public @NonNull Builder setHasGeofencing(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_GEOFENCING, capable); + return this; + } + + /** + * Sets measurements capability. + */ + public @NonNull Builder setHasMeasurements(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_MEASUREMENTS, capable); + return this; + } + + /** + * Sets navigation messages capability. + */ + public @NonNull Builder setHasNavigationMessages(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_NAV_MESSAGES, capable); + return this; + } + + /** + * Sets low power mode capability. + * + * @hide + */ + @SystemApi + public @NonNull Builder setHasLowPowerMode(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_LOW_POWER_MODE, capable); + return this; + } + + /** + * Sets satellite blocklist capability. + * + * @hide + */ + @SystemApi + public @NonNull Builder setHasSatelliteBlocklist(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_SATELLITE_BLOCKLIST, capable); + return this; + } + + /** + * Sets measurement corrections capability. + * + * @hide + */ + @SystemApi + public @NonNull Builder setHasMeasurementCorrections(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_MEASUREMENT_CORRECTIONS, capable); + return this; + } + + /** + * Sets antenna info capability. + */ + public @NonNull Builder setHasAntennaInfo(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_ANTENNA_INFO, capable); + return this; + } + + /** + * Sets measurement corrections line-of-sight satellites capabilitity. + * + * @hide + */ + @SystemApi + public @NonNull Builder setHasMeasurementCorrectionsLosSats(boolean capable) { + mMeasurementCorrectionsFlags = setFlag(mMeasurementCorrectionsFlags, + SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_LOS_SATS, capable); + return this; + } + + /** + * Sets measurement corrections excess path length capabilitity. + * + * @hide + */ + @SystemApi + public @NonNull Builder setHasMeasurementCorrectionsExcessPathLength(boolean capable) { + mMeasurementCorrectionsFlags = setFlag(mMeasurementCorrectionsFlags, + SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_EXCESS_PATH_LENGTH, capable); + return this; + } + + /** + * Sets measurement corrections reflecting plane capabilitity. + * + * @hide + */ + @SystemApi + public @NonNull Builder setHasMeasurementCorrectionsReflectingPlane(boolean capable) { + mMeasurementCorrectionsFlags = setFlag(mMeasurementCorrectionsFlags, + SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_REFLECTING_PLANE, capable); + return this; + } + + /** + * Sets power totals capabilitity. + * + * @hide + */ + public @NonNull Builder setHasPowerTotal(boolean capable) { + mPowerFlags = setFlag(mPowerFlags, SUB_HAL_POWER_CAPABILITY_TOTAL, capable); + return this; + } + + /** + * Sets power single-band tracking capabilitity. + * + * @hide + */ + public @NonNull Builder setHasPowerSinglebandTracking(boolean capable) { + mPowerFlags = setFlag(mPowerFlags, SUB_HAL_POWER_CAPABILITY_SINGLEBAND_TRACKING, + capable); + return this; + } + + /** + * Sets power multi-band tracking capabilitity. + * + * @hide + */ + public @NonNull Builder setHasPowerMultibandTracking(boolean capable) { + mPowerFlags = setFlag(mPowerFlags, SUB_HAL_POWER_CAPABILITY_MULTIBAND_TRACKING, + capable); + return this; + } + + /** + * Sets power single-band acquisition capabilitity. + * + * @hide + */ + public @NonNull Builder setHasPowerSinglebandAcquisition(boolean capable) { + mPowerFlags = setFlag(mPowerFlags, SUB_HAL_POWER_CAPABILITY_SINGLEBAND_ACQUISITION, + capable); + return this; + } + + /** + * Sets power multi-band acquisition capabilitity. + * + * @hide + */ + public @NonNull Builder setHasPowerMultibandAcquisition(boolean capable) { + mPowerFlags = setFlag(mPowerFlags, SUB_HAL_POWER_CAPABILITY_MULTIBAND_ACQUISITION, + capable); + return this; + } + + /** + * Sets power other modes capabilitity. + * + * @hide + */ + public @NonNull Builder setHasPowerOtherModes(boolean capable) { + mPowerFlags = setFlag(mPowerFlags, SUB_HAL_POWER_CAPABILITY_OTHER_MODES, capable); + return this; + } + + /** + * Builds a new GnssCapabilities. + */ + public @NonNull GnssCapabilities build() { + return new GnssCapabilities(mTopFlags, mMeasurementCorrectionsFlags, mPowerFlags); + } + + private static int setFlag(int value, int flag, boolean set) { + if (set) { + return value | flag; + } else { + return value & ~flag; + } + } } } diff --git a/location/java/android/location/IGnssNmeaListener.aidl b/location/java/android/location/IGnssNmeaListener.aidl new file mode 100644 index 0000000000000..c67cc897ea870 --- /dev/null +++ b/location/java/android/location/IGnssNmeaListener.aidl @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2020, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.location; + +/** + * {@hide} + */ +oneway interface IGnssNmeaListener +{ + void onNmeaReceived(long timestamp, String nmea); +} \ No newline at end of file diff --git a/location/java/android/location/IGnssStatusListener.aidl b/location/java/android/location/IGnssStatusListener.aidl index 57b1268f8aafb..c25046e3def82 100644 --- a/location/java/android/location/IGnssStatusListener.aidl +++ b/location/java/android/location/IGnssStatusListener.aidl @@ -27,5 +27,4 @@ oneway interface IGnssStatusListener void onGnssStopped(); void onFirstFix(int ttff); void onSvStatusChanged(in GnssStatus gnssStatus); - void onNmeaReceived(long timestamp, String nmea); } diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index 1dbc98d6c996f..621fe1ba14324 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -21,6 +21,7 @@ import android.location.Address; import android.location.Criteria; import android.location.GeocoderParams; import android.location.Geofence; +import android.location.GnssCapabilities; import android.location.GnssMeasurementCorrections; import android.location.GnssMeasurementRequest; import android.location.IGeocodeListener; @@ -28,6 +29,7 @@ import android.location.IGnssAntennaInfoListener; import android.location.IGnssMeasurementsListener; import android.location.IGnssStatusListener; import android.location.IGnssNavigationMessageListener; +import android.location.IGnssNmeaListener; import android.location.ILocationCallback; import android.location.ILocationListener; import android.location.LastLocationRequest; @@ -70,13 +72,16 @@ interface ILocationManager double upperRightLatitude, double upperRightLongitude, int maxResults, in GeocoderParams params, in IGeocodeListener listener); - long getGnssCapabilities(); + GnssCapabilities getGnssCapabilities(); int getGnssYearOfHardware(); String getGnssHardwareModelName(); void registerGnssStatusCallback(in IGnssStatusListener callback, String packageName, String attributionTag); void unregisterGnssStatusCallback(in IGnssStatusListener callback); + void registerGnssNmeaCallback(in IGnssNmeaListener callback, String packageName, String attributionTag); + void unregisterGnssNmeaCallback(in IGnssNmeaListener callback); + void addGnssMeasurementsListener(in GnssMeasurementRequest request, in IGnssMeasurementsListener listener, String packageName, String attributionTag); void removeGnssMeasurementsListener(in IGnssMeasurementsListener listener); void injectGnssMeasurementCorrections(in GnssMeasurementCorrections corrections); diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index b0ee3246bcd86..00381a68a2a22 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -380,6 +380,8 @@ public class LocationManager { @GuardedBy("mLock") @Nullable private GnssStatusTransportMultiplexer mGnssStatusTransportMultiplexer; @GuardedBy("mLock") + @Nullable private GnssNmeaTransportMultiplexer mGnssNmeaTransportMultiplexer; + @GuardedBy("mLock") @Nullable private GnssMeasurementsTransportMultiplexer mGnssMeasurementsTransportMultiplexer; @GuardedBy("mLock") @Nullable private GnssNavigationTransportMultiplexer mGnssNavigationTransportMultiplexer; @@ -403,6 +405,15 @@ public class LocationManager { } } + private GnssNmeaTransportMultiplexer getGnssNmeaTransportMultiplexer() { + synchronized (mLock) { + if (mGnssNmeaTransportMultiplexer == null) { + mGnssNmeaTransportMultiplexer = new GnssNmeaTransportMultiplexer(); + } + return mGnssNmeaTransportMultiplexer; + } + } + private GnssMeasurementsTransportMultiplexer getGnssMeasurementsTransportMultiplexer() { synchronized (mLock) { if (mGnssMeasurementsTransportMultiplexer == null) { @@ -2092,20 +2103,15 @@ public class LocationManager { */ public @NonNull GnssCapabilities getGnssCapabilities() { try { - long gnssCapabilities = mService.getGnssCapabilities(); - if (gnssCapabilities == GnssCapabilities.INVALID_CAPABILITIES) { - gnssCapabilities = 0L; - } - return GnssCapabilities.of(gnssCapabilities); + return mService.getGnssCapabilities(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** - * Returns the model year of the GNSS hardware and software build. More details, such as build - * date, may be available in {@link #getGnssHardwareModelName()}. May return 0 if the model year - * is less than 2016. + * Returns the model year of the GNSS hardware and software build, or 0 if the model year + * is before 2016. */ public int getGnssYearOfHardware() { try { @@ -2116,13 +2122,10 @@ public class LocationManager { } /** - * Returns the Model Name (including Vendor and Hardware/Software Version) of the GNSS hardware - * driver. + * Returns the model name (including vendor and hardware/software version) of the GNSS hardware + * driver, or null if this information is not available. * - *

No device-specific serial number or ID is returned from this API. - * - *

Will return null when the GNSS hardware abstraction layer does not support providing - * this value. + *

No device-specific serial number or ID is returned from this API. */ @Nullable public String getGnssHardwareModelName() { @@ -2217,8 +2220,11 @@ public class LocationManager { * Registers a GNSS status callback. This method must be called from a {@link Looper} thread, * and callbacks will occur on that looper. * - * @param callback GNSS status callback object to register - * @return true if the listener was successfully added + *

See {@link #registerGnssStatusCallback(Executor, GnssStatus.Callback)} for more detail on + * how this method works. + * + * @param callback the callback to register + * @return {@code true} always * * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present * @@ -2234,9 +2240,12 @@ public class LocationManager { /** * Registers a GNSS status callback. * - * @param callback GNSS status callback object to register - * @param handler a handler with a looper that the callback runs on - * @return true if the listener was successfully added + *

See {@link #registerGnssStatusCallback(Executor, GnssStatus.Callback)} for more detail on + * how this method works. + * + * @param callback the callback to register + * @param handler the handler the callback runs on + * @return {@code true} always * * @throws IllegalArgumentException if callback is null * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present @@ -2252,11 +2261,12 @@ public class LocationManager { } /** - * Registers a GNSS status callback. + * Registers a GNSS status callback. GNSS status information will only be received while the + * {@link #GPS_PROVIDER} is enabled, and while the client app is in the foreground. * * @param executor the executor that the callback runs on - * @param callback GNSS status callback object to register - * @return true if the listener was successfully added + * @param callback the callback to register + * @return {@code true} always * * @throws IllegalArgumentException if executor is null * @throws IllegalArgumentException if callback is null @@ -2301,8 +2311,12 @@ public class LocationManager { /** * Adds an NMEA listener. * - * @param listener a {@link OnNmeaMessageListener} object to register - * @return true if the listener was successfully added + *

See {@link #addNmeaListener(Executor, OnNmeaMessageListener)} for more detail on how this + * method works. + * + * @param listener the listener to register + * @return {@code true} always + * * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present * @deprecated Use {@link #addNmeaListener(OnNmeaMessageListener, Handler)} or {@link * #addNmeaListener(Executor, OnNmeaMessageListener)} instead. @@ -2316,9 +2330,12 @@ public class LocationManager { /** * Adds an NMEA listener. * - * @param listener a {@link OnNmeaMessageListener} object to register - * @param handler a handler with the looper that the listener runs on. - * @return true if the listener was successfully added + *

See {@link #addNmeaListener(Executor, OnNmeaMessageListener)} for more detail on how this + * method works. + * + * @param listener the listener to register + * @param handler the handler that the listener runs on + * @return {@code true} always * * @throws IllegalArgumentException if listener is null * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present @@ -2334,11 +2351,12 @@ public class LocationManager { } /** - * Adds an NMEA listener. + * Adds an NMEA listener. GNSS NMEA information will only be received while the + * {@link #GPS_PROVIDER} is enabled, and while the client app is in the foreground. * - * @param listener a {@link OnNmeaMessageListener} object to register - * @param executor the {@link Executor} that the listener runs on. - * @return true if the listener was successfully added + * @param listener the listener to register + * @param executor the executor that the listener runs on + * @return {@code true} always * * @throws IllegalArgumentException if executor is null * @throws IllegalArgumentException if listener is null @@ -2348,7 +2366,7 @@ public class LocationManager { public boolean addNmeaListener( @NonNull @CallbackExecutor Executor executor, @NonNull OnNmeaMessageListener listener) { - getGnssStatusTransportMultiplexer().addListener(listener, executor); + getGnssNmeaTransportMultiplexer().addListener(listener, executor); return true; } @@ -2358,7 +2376,7 @@ public class LocationManager { * @param listener a {@link OnNmeaMessageListener} object to remove */ public void removeNmeaListener(@NonNull OnNmeaMessageListener listener) { - getGnssStatusTransportMultiplexer().removeListener(listener); + getGnssNmeaTransportMultiplexer().removeListener(listener); } /** @@ -2386,10 +2404,14 @@ public class LocationManager { public void removeGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {} /** - * Registers a GPS Measurement callback which will run on a binder thread. + * Registers a GNSS measurements callback which will run on a binder thread. + * + *

See {@link #registerGnssMeasurementsCallback(Executor, GnssMeasurementsEvent.Callback) + * for more detail on how this method works. + * + * @param callback a {@link GnssMeasurementsEvent.Callback} object to register + * @return {@code true} always * - * @param callback a {@link GnssMeasurementsEvent.Callback} object to register. - * @return {@code true} if the callback was added successfully, {@code false} otherwise. * @deprecated Use {@link * #registerGnssMeasurementsCallback(GnssMeasurementsEvent.Callback, Handler)} or {@link * #registerGnssMeasurementsCallback(Executor, GnssMeasurementsEvent.Callback)} instead. @@ -2402,11 +2424,14 @@ public class LocationManager { } /** - * Registers a GPS Measurement callback. + * Registers a GNSS measurements callback. * - * @param callback a {@link GnssMeasurementsEvent.Callback} object to register. - * @param handler the handler that the callback runs on. - * @return {@code true} if the callback was added successfully, {@code false} otherwise. + *

See {@link #registerGnssMeasurementsCallback(Executor, GnssMeasurementsEvent.Callback) + * for more detail on how this method works. + * + * @param callback a {@link GnssMeasurementsEvent.Callback} object to register + * @param handler the handler that the callback runs on + * @return {@code true} always * * @throws IllegalArgumentException if callback is null * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present @@ -2423,11 +2448,14 @@ public class LocationManager { } /** - * Registers a GPS Measurement callback. + * Registers a GNSS measurements callback. GNSS measurements information will only be received + * while the {@link #GPS_PROVIDER} is enabled, and while the client app is in the foreground. * - * @param callback a {@link GnssMeasurementsEvent.Callback} object to register. - * @param executor the executor that the callback runs on. - * @return {@code true} if the callback was added successfully, {@code false} otherwise. + *

Not all GNSS chipsets support measurements updates, see {@link #getGnssCapabilities()}. + * + * @param executor the executor that the callback runs on + * @param callback the callback to register + * @return {@code true} always * * @throws IllegalArgumentException if executor is null * @throws IllegalArgumentException if callback is null @@ -2444,12 +2472,11 @@ public class LocationManager { /** * Registers a GNSS Measurement callback. * - * @param request extra parameters to pass to GNSS measurement provider. For example, if {@link - * GnssRequest#isFullTracking()} is true, GNSS chipset switches off duty - * cycling. - * @param executor the executor that the callback runs on. - * @param callback a {@link GnssMeasurementsEvent.Callback} object to register. - * @return {@code true} if the callback was added successfully, {@code false} otherwise. + * @param request the gnss measurement request containgin measurement parameters + * @param executor the executor that the callback runs on + * @param callback the callack to register + * @return {@code true} always + * * @throws IllegalArgumentException if request is null * @throws IllegalArgumentException if executor is null * @throws IllegalArgumentException if callback is null @@ -2498,8 +2525,7 @@ public class LocationManager { /** * Injects GNSS measurement corrections into the GNSS chipset. * - * @param measurementCorrections a {@link GnssMeasurementCorrections} object with the GNSS - * measurement corrections to be injected into the GNSS chipset. + * @param measurementCorrections measurement corrections to be injected into the chipset * * @throws IllegalArgumentException if measurementCorrections is null * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present @@ -2528,12 +2554,14 @@ public class LocationManager { } /** - * Registers a Gnss Antenna Info listener. Only expect results if - * {@link GnssCapabilities#hasGnssAntennaInfo()} shows that antenna info is supported. + * Registers a GNSS antenna info listener. GNSS antenna info updates will only be received while + * the {@link #GPS_PROVIDER} is enabled, and while the client app is in the foreground. * - * @param executor the executor that the listener runs on. - * @param listener a {@link GnssAntennaInfo.Listener} object to register. - * @return {@code true} if the listener was added successfully, {@code false} otherwise. + *

Not all GNSS chipsets support antenna info updates, see {@link #getGnssCapabilities()}. + * + * @param executor the executor that the listener runs on + * @param listener the listener to register + * @return {@code true} always * * @throws IllegalArgumentException if executor is null * @throws IllegalArgumentException if listener is null @@ -2550,7 +2578,7 @@ public class LocationManager { /** * Unregisters a GNSS Antenna Info listener. * - * @param listener a {@link GnssAntennaInfo.Listener} object to remove. + * @param listener a {@link GnssAntennaInfo.Listener} object to remove */ public void unregisterAntennaInfoListener(@NonNull GnssAntennaInfo.Listener listener) { getGnssAntennaInfoTransportMultiplexer().removeListener(listener); @@ -2581,10 +2609,15 @@ public class LocationManager { public void removeGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) {} /** - * Registers a GNSS Navigation Message callback which will run on a binder thread. + * Registers a GNSS navigation message callback which will run on a binder thread. + * + *

See + * {@link #registerGnssNavigationMessageCallback(Executor, GnssNavigationMessage.Callback)} for + * more detail on how this method works. + * + * @param callback the callback to register + * @return {@code true} always * - * @param callback a {@link GnssNavigationMessage.Callback} object to register. - * @return {@code true} if the callback was added successfully, {@code false} otherwise. * @deprecated Use {@link * #registerGnssNavigationMessageCallback(GnssNavigationMessage.Callback, Handler)} or {@link * #registerGnssNavigationMessageCallback(Executor, GnssNavigationMessage.Callback)} instead. @@ -2596,11 +2629,15 @@ public class LocationManager { } /** - * Registers a GNSS Navigation Message callback. + * Registers a GNSS navigation message callback. * - * @param callback a {@link GnssNavigationMessage.Callback} object to register. - * @param handler the handler that the callback runs on. - * @return {@code true} if the callback was added successfully, {@code false} otherwise. + *

See + * {@link #registerGnssNavigationMessageCallback(Executor, GnssNavigationMessage.Callback)} for + * more detail on how this method works. + * + * @param callback the callback to register + * @param handler the handler that the callback runs on + * @return {@code true} always * * @throws IllegalArgumentException if callback is null * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present @@ -2616,11 +2653,15 @@ public class LocationManager { } /** - * Registers a GNSS Navigation Message callback. + * Registers a GNSS navigation message callback. GNSS navigation messages will only be received + * while the {@link #GPS_PROVIDER} is enabled, and while the client app is in the foreground. * - * @param callback a {@link GnssNavigationMessage.Callback} object to register. - * @param executor the looper that the callback runs on. - * @return {@code true} if the callback was added successfully, {@code false} otherwise. + *

Not all GNSS chipsets support navigation message updates, see + * {@link #getGnssCapabilities()}. + * + * @param executor the executor that the callback runs on + * @param callback the callback to register + * @return {@code true} always * * @throws IllegalArgumentException if executor is null * @throws IllegalArgumentException if callback is null @@ -2854,20 +2895,6 @@ public class LocationManager { } } - private static class NmeaAdapter extends GnssStatus.Callback implements OnNmeaMessageListener { - - private final OnNmeaMessageListener mListener; - - NmeaAdapter(OnNmeaMessageListener listener) { - mListener = listener; - } - - @Override - public void onNmeaMessage(String message, long timestamp) { - mListener.onNmeaMessage(message, timestamp); - } - } - private static class GpsAdapter extends GnssStatus.Callback { private final GpsStatus.Listener mGpsListener; @@ -2915,11 +2942,6 @@ public class LocationManager { return mTtff; } - public void addListener(@NonNull OnNmeaMessageListener listener, - @NonNull Executor executor) { - addListener(listener, null, new NmeaAdapter(listener), executor); - } - public void addListener(@NonNull GpsStatus.Listener listener, @NonNull Executor executor) { addListener(listener, null, new GpsAdapter(listener), executor); } @@ -2972,14 +2994,51 @@ public class LocationManager { mGnssStatus = gnssStatus; deliverToListeners(callback -> callback.onSatelliteStatusChanged(gnssStatus)); } + } + } + + private class GnssNmeaTransportMultiplexer extends + ListenerTransportMultiplexer { + + private @Nullable IGnssNmeaListener mListenerTransport; + + GnssNmeaTransportMultiplexer() {} + + public void addListener(@NonNull OnNmeaMessageListener listener, + @NonNull Executor executor) { + addListener(listener, null, listener, executor); + } + + @Override + protected void registerWithServer(Void ignored) throws RemoteException { + IGnssNmeaListener transport = mListenerTransport; + if (transport == null) { + transport = new GnssNmeaListener(); + } + + // if a remote exception is thrown the transport should not be set + mListenerTransport = null; + mService.registerGnssNmeaCallback(transport, mContext.getPackageName(), + mContext.getAttributionTag()); + mListenerTransport = transport; + } + + @Override + protected void unregisterWithServer() throws RemoteException { + if (mListenerTransport != null) { + IGnssNmeaListener transport = mListenerTransport; + mListenerTransport = null; + mService.unregisterGnssNmeaCallback(transport); + } + } + + private class GnssNmeaListener extends IGnssNmeaListener.Stub { + + GnssNmeaListener() {} @Override public void onNmeaReceived(long timestamp, String nmea) { - deliverToListeners((callback) -> { - if (callback instanceof NmeaAdapter) { - ((NmeaAdapter) callback).onNmeaMessage(nmea, timestamp); - } - }); + deliverToListeners(callback -> callback.onNmeaMessage(nmea, timestamp)); } } } diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java index 0de2ae24bad76..372bceeea3c48 100644 --- a/services/core/java/com/android/server/location/LocationManagerService.java +++ b/services/core/java/com/android/server/location/LocationManagerService.java @@ -52,8 +52,8 @@ import android.location.IGeocodeListener; import android.location.IGnssAntennaInfoListener; import android.location.IGnssMeasurementsListener; import android.location.IGnssNavigationMessageListener; +import android.location.IGnssNmeaListener; import android.location.IGnssStatusListener; -import android.location.IGpsGeofenceHardware; import android.location.ILocationCallback; import android.location.ILocationListener; import android.location.ILocationManager; @@ -87,10 +87,13 @@ import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.location.geofence.GeofenceManager; import com.android.server.location.geofence.GeofenceProxy; +import com.android.server.location.gnss.GnssConfiguration; import com.android.server.location.gnss.GnssManagerService; +import com.android.server.location.gnss.hal.GnssNative; import com.android.server.location.injector.AlarmHelper; import com.android.server.location.injector.AppForegroundHelper; import com.android.server.location.injector.AppOpsHelper; +import com.android.server.location.injector.EmergencyHelper; import com.android.server.location.injector.Injector; import com.android.server.location.injector.LocationAttributionHelper; import com.android.server.location.injector.LocationEventLog; @@ -102,6 +105,7 @@ import com.android.server.location.injector.SettingsHelper; import com.android.server.location.injector.SystemAlarmHelper; import com.android.server.location.injector.SystemAppForegroundHelper; import com.android.server.location.injector.SystemAppOpsHelper; +import com.android.server.location.injector.SystemEmergencyHelper; import com.android.server.location.injector.SystemLocationPermissionsHelper; import com.android.server.location.injector.SystemLocationPowerSaveModeHelper; import com.android.server.location.injector.SystemScreenInteractiveHelper; @@ -367,8 +371,10 @@ public class LocationManagerService extends ILocationManager.Stub { // initialize gnss last because it has no awareness of boot phases and blindly assumes that // all other location providers are loaded at initialization - if (GnssManagerService.isGnssSupported()) { - mGnssManagerService = new GnssManagerService(mContext, mInjector); + if (GnssNative.isSupported()) { + GnssConfiguration gnssConfiguration = new GnssConfiguration(mContext); + GnssNative gnssNative = GnssNative.create(mInjector, gnssConfiguration); + mGnssManagerService = new GnssManagerService(mContext, mInjector, gnssNative); mGnssManagerService.onSystemReady(); LocationProviderManager gnssManager = new LocationProviderManager(mContext, mInjector, @@ -390,13 +396,11 @@ public class LocationManagerService extends ILocationManager.Stub { } // bind to gnss geofence proxy - if (GnssManagerService.isGnssSupported()) { - IGpsGeofenceHardware gpsGeofenceHardware = mGnssManagerService.getGpsGeofenceProxy(); - if (gpsGeofenceHardware != null) { - GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, gpsGeofenceHardware); - if (provider == null) { - Log.e(TAG, "unable to bind to GeofenceProxy"); - } + if (mGnssManagerService != null) { + GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, + mGnssManagerService.getGnssGeofenceProxy()); + if (provider == null) { + Log.e(TAG, "unable to bind to GeofenceProxy"); } } @@ -863,6 +867,21 @@ public class LocationManagerService extends ILocationManager.Stub { } } + @Override + public void registerGnssNmeaCallback(IGnssNmeaListener listener, String packageName, + String attributionTag) { + if (mGnssManagerService != null) { + mGnssManagerService.registerGnssNmeaCallback(listener, packageName, attributionTag); + } + } + + @Override + public void unregisterGnssNmeaCallback(IGnssNmeaListener listener) { + if (mGnssManagerService != null) { + mGnssManagerService.unregisterGnssNmeaCallback(listener); + } + } + @Override public void addGnssMeasurementsListener(@Nullable GnssMeasurementRequest request, IGnssMeasurementsListener listener, String packageName, String attributionTag) { @@ -888,8 +907,8 @@ public class LocationManagerService extends ILocationManager.Stub { } @Override - public long getGnssCapabilities() { - return mGnssManagerService == null ? GnssCapabilities.INVALID_CAPABILITIES + public GnssCapabilities getGnssCapabilities() { + return mGnssManagerService == null ? new GnssCapabilities.Builder().build() : mGnssManagerService.getGnssCapabilities(); } @@ -1289,8 +1308,10 @@ public class LocationManagerService extends ILocationManager.Stub { private static class SystemInjector implements Injector { - private final LocationEventLog mLocationEventLog; + private final Context mContext; + private final UserInfoHelper mUserInfoHelper; + private final LocationEventLog mLocationEventLog; private final AlarmHelper mAlarmHelper; private final SystemAppOpsHelper mAppOpsHelper; private final SystemLocationPermissionsHelper mLocationPermissionsHelper; @@ -1301,9 +1322,19 @@ public class LocationManagerService extends ILocationManager.Stub { private final LocationAttributionHelper mLocationAttributionHelper; private final LocationUsageLogger mLocationUsageLogger; + // lazily instantiated since they may not always be used + + @GuardedBy("this") + private @Nullable SystemEmergencyHelper mEmergencyCallHelper; + + @GuardedBy("this") + private boolean mSystemReady; + SystemInjector(Context context, UserInfoHelper userInfoHelper) { - mLocationEventLog = new LocationEventLog(); + mContext = context; + mUserInfoHelper = userInfoHelper; + mLocationEventLog = new LocationEventLog(); mAlarmHelper = new SystemAlarmHelper(context); mAppOpsHelper = new SystemAppOpsHelper(context); mLocationPermissionsHelper = new SystemLocationPermissionsHelper(context, @@ -1317,13 +1348,19 @@ public class LocationManagerService extends ILocationManager.Stub { mLocationUsageLogger = new LocationUsageLogger(); } - void onSystemReady() { + synchronized void onSystemReady() { mAppOpsHelper.onSystemReady(); mLocationPermissionsHelper.onSystemReady(); mSettingsHelper.onSystemReady(); mAppForegroundHelper.onSystemReady(); mLocationPowerSaveModeHelper.onSystemReady(); mScreenInteractiveHelper.onSystemReady(); + + if (mEmergencyCallHelper != null) { + mEmergencyCallHelper.onSystemReady(); + } + + mSystemReady = true; } @Override @@ -1356,11 +1393,6 @@ public class LocationManagerService extends ILocationManager.Stub { return mAppForegroundHelper; } - @Override - public LocationUsageLogger getLocationUsageLogger() { - return mLocationUsageLogger; - } - @Override public LocationPowerSaveModeHelper getLocationPowerSaveModeHelper() { return mLocationPowerSaveModeHelper; @@ -1376,9 +1408,26 @@ public class LocationManagerService extends ILocationManager.Stub { return mLocationAttributionHelper; } + @Override + public synchronized EmergencyHelper getEmergencyHelper() { + if (mEmergencyCallHelper == null) { + mEmergencyCallHelper = new SystemEmergencyHelper(mContext); + if (mSystemReady) { + mEmergencyCallHelper.onSystemReady(); + } + } + + return mEmergencyCallHelper; + } + @Override public LocationEventLog getLocationEventLog() { return mLocationEventLog; } + + @Override + public LocationUsageLogger getLocationUsageLogger() { + return mLocationUsageLogger; + } } } diff --git a/services/core/java/com/android/server/location/gnss/GnssAntennaInfoProvider.java b/services/core/java/com/android/server/location/gnss/GnssAntennaInfoProvider.java index 9961d274ea9c4..e9f79efb05130 100644 --- a/services/core/java/com/android/server/location/gnss/GnssAntennaInfoProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssAntennaInfoProvider.java @@ -20,12 +20,12 @@ import static com.android.server.location.gnss.GnssManagerService.D; import static com.android.server.location.gnss.GnssManagerService.TAG; import android.location.GnssAntennaInfo; +import android.location.GnssCapabilities; import android.location.IGnssAntennaInfoListener; import android.location.util.identity.CallerIdentity; import android.util.Log; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Preconditions; +import com.android.server.location.gnss.hal.GnssNative; import com.android.server.location.injector.Injector; import java.util.Collection; @@ -35,23 +35,22 @@ import java.util.List; * Provides GNSS antenna information to clients. */ public class GnssAntennaInfoProvider extends - GnssListenerMultiplexer { + GnssListenerMultiplexer implements + GnssNative.BaseCallbacks, GnssNative.AntennaInfoCallbacks { - private final GnssAntennaInfoProviderNative mNative; + private final GnssNative mGnssNative; - public GnssAntennaInfoProvider(Injector injector) { - this(injector, new GnssAntennaInfoProviderNative()); - } - - @VisibleForTesting - public GnssAntennaInfoProvider(Injector injector, GnssAntennaInfoProviderNative aNative) { + public GnssAntennaInfoProvider(Injector injector, GnssNative gnssNative) { super(injector); - mNative = aNative; + mGnssNative = gnssNative; + + mGnssNative.addBaseCallbacks(this); + mGnssNative.addAntennaInfoCallbacks(this); } @Override protected boolean isServiceSupported() { - return mNative.isAntennaInfoSupported(); + return mGnssNative.isAntennaInfoListeningSupported(); } @Override @@ -62,9 +61,7 @@ public class GnssAntennaInfoProvider extends @Override protected boolean registerWithService(Void ignored, Collection registrations) { - Preconditions.checkState(mNative.isAntennaInfoSupported()); - - if (mNative.startAntennaInfoListening()) { + if (mGnssNative.startAntennaInfoListening()) { if (D) { Log.d(TAG, "starting gnss antenna info"); } @@ -77,7 +74,7 @@ public class GnssAntennaInfoProvider extends @Override protected void unregisterWithService() { - if (mNative.stopAntennaInfoListening()) { + if (mGnssNative.stopAntennaInfoListening()) { if (D) { Log.d(TAG, "stopping gnss antenna info"); } @@ -86,39 +83,19 @@ public class GnssAntennaInfoProvider extends } } - /** - * Called by GnssLocationProvider. - */ - public void onGnssAntennaInfoAvailable(List gnssAntennaInfos) { - deliverToListeners((listener) -> { - listener.onGnssAntennaInfoReceived(gnssAntennaInfos); + @Override + public void onHalRestarted() { + resetService(); + } + + @Override + public void onCapabilitiesChanged(GnssCapabilities oldCapabilities, + GnssCapabilities newCapabilities) {} + + @Override + public void onReportAntennaInfo(List antennaInfos) { + deliverToListeners(listener -> { + listener.onGnssAntennaInfoReceived(antennaInfos); }); } - - /** - * Wrapper class for native methods. This is mocked for testing. - */ - @VisibleForTesting - public static class GnssAntennaInfoProviderNative { - - public boolean isAntennaInfoSupported() { - return native_is_antenna_info_supported(); - } - - /** Start antenna info listening. */ - public boolean startAntennaInfoListening() { - return native_start_antenna_info_listening(); - } - - /** Stop antenna info listening. */ - public boolean stopAntennaInfoListening() { - return native_stop_antenna_info_listening(); - } - } - - static native boolean native_is_antenna_info_supported(); - - static native boolean native_start_antenna_info_listening(); - - static native boolean native_stop_antenna_info_listening(); } diff --git a/services/core/java/com/android/server/location/gnss/GnssCapabilitiesProvider.java b/services/core/java/com/android/server/location/gnss/GnssCapabilitiesProvider.java deleted file mode 100644 index 1c4fb10b8d0ee..0000000000000 --- a/services/core/java/com/android/server/location/gnss/GnssCapabilitiesProvider.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.location.gnss; - -import android.location.GnssCapabilities; -import android.util.Log; - -import com.android.internal.annotations.GuardedBy; - -/** - * Provides GNSS capabilities supported by the GNSS HAL implementation. - */ -public class GnssCapabilitiesProvider { - private static final String TAG = "GnssCapabilitiesProvider"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - private static final long GNSS_CAPABILITIES_TOP_HAL = - GnssCapabilities.LOW_POWER_MODE | GnssCapabilities.SATELLITE_BLOCKLIST - | GnssCapabilities.GEOFENCING | GnssCapabilities.MEASUREMENTS - | GnssCapabilities.NAV_MESSAGES; - - private static final long GNSS_CAPABILITIES_SUB_HAL_MEASUREMENT_CORRECTIONS = - GnssCapabilities.MEASUREMENT_CORRECTIONS - | GnssCapabilities.MEASUREMENT_CORRECTIONS_LOS_SATS - | GnssCapabilities.MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH - | GnssCapabilities.MEASUREMENT_CORRECTIONS_REFLECTING_PLANE; - - // Capabilities in {@link android.location.GnssCapabilities} supported by GNSS chipset. - @GuardedBy("this") - private long mGnssCapabilities; - - /** - * Returns the capabilities supported by the GNSS chipset. - * - *

The capabilities are described in {@link android.location.GnssCapabilities} and - * their integer values correspond to the bit positions in the returned {@code long} value. - */ - public long getGnssCapabilities() { - synchronized (this) { - return mGnssCapabilities; - } - } - - /** - * Updates the general capabilities exposed through {@link android.location.GnssCapabilities}. - */ - void setTopHalCapabilities(int topHalCapabilities) { - long gnssCapabilities = 0; - if (hasCapability(topHalCapabilities, - GnssLocationProvider.GPS_CAPABILITY_LOW_POWER_MODE)) { - gnssCapabilities |= GnssCapabilities.LOW_POWER_MODE; - } - if (hasCapability(topHalCapabilities, - GnssLocationProvider.GPS_CAPABILITY_SATELLITE_BLOCKLIST)) { - gnssCapabilities |= GnssCapabilities.SATELLITE_BLOCKLIST; - } - if (hasCapability(topHalCapabilities, GnssLocationProvider.GPS_CAPABILITY_GEOFENCING)) { - gnssCapabilities |= GnssCapabilities.GEOFENCING; - } - if (hasCapability(topHalCapabilities, GnssLocationProvider.GPS_CAPABILITY_MEASUREMENTS)) { - gnssCapabilities |= GnssCapabilities.MEASUREMENTS; - } - if (hasCapability(topHalCapabilities, GnssLocationProvider.GPS_CAPABILITY_NAV_MESSAGES)) { - gnssCapabilities |= GnssCapabilities.NAV_MESSAGES; - } - if (hasCapability(topHalCapabilities, GnssLocationProvider.GPS_CAPABILITY_ANTENNA_INFO)) { - gnssCapabilities |= GnssCapabilities.ANTENNA_INFO; - } - - synchronized (this) { - mGnssCapabilities &= ~GNSS_CAPABILITIES_TOP_HAL; - mGnssCapabilities |= gnssCapabilities; - if (DEBUG) { - Log.d(TAG, "setTopHalCapabilities, mGnssCapabilities=0x" + Long.toHexString( - mGnssCapabilities) + ", " + GnssCapabilities.of(mGnssCapabilities)); - } - } - } - - /** - * Updates the measurement corrections related capabilities exposed through - * {@link android.location.GnssCapabilities}. - */ - void setSubHalMeasurementCorrectionsCapabilities(int measurementCorrectionsCapabilities) { - long gnssCapabilities = GnssCapabilities.MEASUREMENT_CORRECTIONS; - if (hasCapability(measurementCorrectionsCapabilities, - GnssMeasurementCorrectionsProvider.CAPABILITY_LOS_SATS)) { - gnssCapabilities |= GnssCapabilities.MEASUREMENT_CORRECTIONS_LOS_SATS; - } - if (hasCapability(measurementCorrectionsCapabilities, - GnssMeasurementCorrectionsProvider.CAPABILITY_EXCESS_PATH_LENGTH)) { - gnssCapabilities |= GnssCapabilities.MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH; - } - if (hasCapability(measurementCorrectionsCapabilities, - GnssMeasurementCorrectionsProvider.CAPABILITY_REFLECTING_PLANE)) { - gnssCapabilities |= GnssCapabilities.MEASUREMENT_CORRECTIONS_REFLECTING_PLANE; - } - - synchronized (this) { - mGnssCapabilities &= ~GNSS_CAPABILITIES_SUB_HAL_MEASUREMENT_CORRECTIONS; - mGnssCapabilities |= gnssCapabilities; - if (DEBUG) { - Log.d(TAG, "setSubHalMeasurementCorrectionsCapabilities, mGnssCapabilities=0x" - + Long.toHexString(mGnssCapabilities) + ", " + GnssCapabilities.of( - mGnssCapabilities)); - } - } - } - - private static boolean hasCapability(int halCapabilities, int capability) { - return (halCapabilities & capability) != 0; - } -} diff --git a/services/core/java/com/android/server/location/gnss/GnssConfiguration.java b/services/core/java/com/android/server/location/gnss/GnssConfiguration.java index 26283729f4e97..60b7447e9f6c8 100644 --- a/services/core/java/com/android/server/location/gnss/GnssConfiguration.java +++ b/services/core/java/com/android/server/location/gnss/GnssConfiguration.java @@ -31,7 +31,7 @@ import libcore.io.IoUtils; import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -48,7 +48,7 @@ import java.util.Properties; * Instances of this class are not thread-safe and should either be used from a single thread * or with external synchronization when used by multiple threads. */ -class GnssConfiguration { +public class GnssConfiguration { private static final String TAG = "GnssConfiguration"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @@ -98,13 +98,13 @@ class GnssConfiguration { /** * Properties loaded from PROPERTIES_FILE. */ - private Properties mProperties; + private final Properties mProperties; private int mEsExtensionSec = 0; private final Context mContext; - GnssConfiguration(Context context) { + public GnssConfiguration(Context context) { mContext = context; mProperties = new Properties(); } @@ -120,7 +120,7 @@ class GnssConfiguration { * Returns the value of config parameter ES_EXTENSION_SEC. The value is range checked * and constrained to min/max limits. */ - int getEsExtensionSec() { + public int getEsExtensionSec() { return mEsExtensionSec; } @@ -168,8 +168,8 @@ class GnssConfiguration { * Returns the value of config parameter SUPL_ES or {@code defaultSuplEs} if no value is * provided or if there is an error parsing the configured value. */ - int getSuplEs(int defaulSuplEs) { - return getIntConfig(CONFIG_SUPL_ES, defaulSuplEs); + public int getSuplEs(int defaultSuplEs) { + return getIntConfig(CONFIG_SUPL_ES, defaultSuplEs); } /** @@ -181,27 +181,21 @@ class GnssConfiguration { } /** - * Returns the list of proxy apps from the value of config parameter NFW_PROXY_APPS or - * {@Collections.EMPTY_LIST} if no value is provided. + * Returns the list of proxy apps from the value of config parameter NFW_PROXY_APPS. */ List getProxyApps() { // Space separated list of Android proxy app package names. String proxyAppsStr = mProperties.getProperty(CONFIG_NFW_PROXY_APPS); if (TextUtils.isEmpty(proxyAppsStr)) { - return Collections.EMPTY_LIST; + return Collections.emptyList(); } String[] proxyAppsArray = proxyAppsStr.trim().split("\\s+"); if (proxyAppsArray.length == 0) { - return Collections.EMPTY_LIST; + return Collections.emptyList(); } - ArrayList proxyApps = new ArrayList(proxyAppsArray.length); - for (String proxyApp : proxyAppsArray) { - proxyApps.add(proxyApp); - } - - return proxyApps; + return Arrays.asList(proxyAppsArray); } /** diff --git a/services/core/java/com/android/server/location/gnss/GnssGeofenceProvider.java b/services/core/java/com/android/server/location/gnss/GnssGeofenceProxy.java similarity index 59% rename from services/core/java/com/android/server/location/gnss/GnssGeofenceProvider.java rename to services/core/java/com/android/server/location/gnss/GnssGeofenceProxy.java index 53883b91c36de..32a7952b14d1d 100644 --- a/services/core/java/com/android/server/location/gnss/GnssGeofenceProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssGeofenceProxy.java @@ -16,20 +16,17 @@ package com.android.server.location.gnss; +import android.location.GnssCapabilities; import android.location.IGpsGeofenceHardware; -import android.util.Log; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; +import com.android.server.location.gnss.hal.GnssNative; /** * Manages GNSS Geofence operations. */ -class GnssGeofenceProvider extends IGpsGeofenceHardware.Stub { - - private static final String TAG = "GnssGeofenceProvider"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); +class GnssGeofenceProxy extends IGpsGeofenceHardware.Stub implements GnssNative.BaseCallbacks { /** Holds the parameters of a geofence. */ private static class GeofenceEntry { @@ -45,43 +42,22 @@ class GnssGeofenceProvider extends IGpsGeofenceHardware.Stub { } private final Object mLock = new Object(); - @GuardedBy("mLock") - private final GnssGeofenceProviderNative mNative; + + private final GnssNative mGnssNative; + @GuardedBy("mLock") private final SparseArray mGeofenceEntries = new SparseArray<>(); - GnssGeofenceProvider() { - this(new GnssGeofenceProviderNative()); - } + GnssGeofenceProxy(GnssNative gnssNative) { + mGnssNative = gnssNative; - @VisibleForTesting - GnssGeofenceProvider(GnssGeofenceProviderNative gnssGeofenceProviderNative) { - mNative = gnssGeofenceProviderNative; - } - - void resumeIfStarted() { - if (DEBUG) { - Log.d(TAG, "resumeIfStarted"); - } - synchronized (mLock) { - for (int i = 0; i < mGeofenceEntries.size(); i++) { - GeofenceEntry entry = mGeofenceEntries.valueAt(i); - boolean added = mNative.addGeofence(entry.geofenceId, entry.latitude, - entry.longitude, - entry.radius, - entry.lastTransition, entry.monitorTransitions, - entry.notificationResponsiveness, entry.unknownTimer); - if (added && entry.paused) { - mNative.pauseGeofence(entry.geofenceId); - } - } - } + mGnssNative.addBaseCallbacks(this); } @Override public boolean isHardwareGeofenceSupported() { synchronized (mLock) { - return mNative.isGeofenceSupported(); + return mGnssNative.isGeofencingSupported(); } } @@ -90,7 +66,7 @@ class GnssGeofenceProvider extends IGpsGeofenceHardware.Stub { double longitude, double radius, int lastTransition, int monitorTransitions, int notificationResponsiveness, int unknownTimer) { synchronized (mLock) { - boolean added = mNative.addGeofence(geofenceId, latitude, longitude, radius, + boolean added = mGnssNative.addGeofence(geofenceId, latitude, longitude, radius, lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer); if (added) { @@ -112,7 +88,7 @@ class GnssGeofenceProvider extends IGpsGeofenceHardware.Stub { @Override public boolean removeHardwareGeofence(int geofenceId) { synchronized (mLock) { - boolean removed = mNative.removeGeofence(geofenceId); + boolean removed = mGnssNative.removeGeofence(geofenceId); if (removed) { mGeofenceEntries.remove(geofenceId); } @@ -123,7 +99,7 @@ class GnssGeofenceProvider extends IGpsGeofenceHardware.Stub { @Override public boolean pauseHardwareGeofence(int geofenceId) { synchronized (mLock) { - boolean paused = mNative.pauseGeofence(geofenceId); + boolean paused = mGnssNative.pauseGeofence(geofenceId); if (paused) { GeofenceEntry entry = mGeofenceEntries.get(geofenceId); if (entry != null) { @@ -137,7 +113,7 @@ class GnssGeofenceProvider extends IGpsGeofenceHardware.Stub { @Override public boolean resumeHardwareGeofence(int geofenceId, int monitorTransitions) { synchronized (mLock) { - boolean resumed = mNative.resumeGeofence(geofenceId, monitorTransitions); + boolean resumed = mGnssNative.resumeGeofence(geofenceId, monitorTransitions); if (resumed) { GeofenceEntry entry = mGeofenceEntries.get(geofenceId); if (entry != null) { @@ -149,41 +125,24 @@ class GnssGeofenceProvider extends IGpsGeofenceHardware.Stub { } } - @VisibleForTesting - static class GnssGeofenceProviderNative { - public boolean isGeofenceSupported() { - return native_is_geofence_supported(); - } - - public boolean addGeofence(int geofenceId, double latitude, double longitude, double radius, - int lastTransition, int monitorTransitions, int notificationResponsiveness, - int unknownTimer) { - return native_add_geofence(geofenceId, latitude, longitude, radius, lastTransition, - monitorTransitions, notificationResponsiveness, unknownTimer); - } - - public boolean removeGeofence(int geofenceId) { - return native_remove_geofence(geofenceId); - } - - public boolean resumeGeofence(int geofenceId, int transitions) { - return native_resume_geofence(geofenceId, transitions); - } - - public boolean pauseGeofence(int geofenceId) { - return native_pause_geofence(geofenceId); + @Override + public void onHalRestarted() { + synchronized (mLock) { + for (int i = 0; i < mGeofenceEntries.size(); i++) { + GeofenceEntry entry = mGeofenceEntries.valueAt(i); + boolean added = mGnssNative.addGeofence(entry.geofenceId, entry.latitude, + entry.longitude, + entry.radius, + entry.lastTransition, entry.monitorTransitions, + entry.notificationResponsiveness, entry.unknownTimer); + if (added && entry.paused) { + mGnssNative.pauseGeofence(entry.geofenceId); + } + } } } - private static native boolean native_is_geofence_supported(); - - private static native boolean native_add_geofence(int geofenceId, double latitude, - double longitude, double radius, int lastTransition, int monitorTransitions, - int notificationResponsivenes, int unknownTimer); - - private static native boolean native_remove_geofence(int geofenceId); - - private static native boolean native_resume_geofence(int geofenceId, int transitions); - - private static native boolean native_pause_geofence(int geofenceId); + @Override + public void onCapabilitiesChanged(GnssCapabilities oldCapabilities, + GnssCapabilities newCapabilities) {} } diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java index 691b85af62d3d..afe75674647fc 100644 --- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java @@ -17,6 +17,28 @@ package com.android.server.location.gnss; import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; +import static com.android.server.location.gnss.hal.GnssNative.AGPS_REF_LOCATION_TYPE_GSM_CELLID; +import static com.android.server.location.gnss.hal.GnssNative.AGPS_REF_LOCATION_TYPE_UMTS_CELLID; +import static com.android.server.location.gnss.hal.GnssNative.AGPS_SETID_TYPE_IMSI; +import static com.android.server.location.gnss.hal.GnssNative.AGPS_SETID_TYPE_MSISDN; +import static com.android.server.location.gnss.hal.GnssNative.AGPS_SETID_TYPE_NONE; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_ALL; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_ALMANAC; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_CELLDB_INFO; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_EPHEMERIS; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_HEALTH; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_IONO; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_POSITION; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_RTI; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_SADATA; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_SVDIR; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_SVSTEER; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_TIME; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_UTC; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_POSITION_MODE_MS_ASSISTED; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_POSITION_MODE_MS_BASED; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_POSITION_MODE_STANDALONE; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_POSITION_RECURRENCE_PERIODIC; import static java.util.concurrent.TimeUnit.MILLISECONDS; @@ -28,14 +50,9 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.database.ContentObserver; -import android.hardware.location.GeofenceHardware; -import android.hardware.location.GeofenceHardwareImpl; -import android.location.FusedBatchOptions; -import android.location.GnssAntennaInfo; -import android.location.GnssMeasurementsEvent; -import android.location.GnssNavigationMessage; +import android.location.Criteria; +import android.location.GnssCapabilities; import android.location.GnssStatus; -import android.location.IGpsGeofenceHardware; import android.location.INetInitiatedListener; import android.location.Location; import android.location.LocationListener; @@ -73,11 +90,11 @@ import com.android.internal.app.IBatteryStats; import com.android.internal.location.GpsNetInitiatedHandler; import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification; import com.android.internal.location.ProviderRequest; -import com.android.internal.location.gnssmetrics.GnssMetrics; import com.android.internal.util.FrameworkStatsLog; import com.android.server.FgThread; import com.android.server.location.gnss.GnssSatelliteBlocklistHelper.GnssSatelliteBlocklistCallback; import com.android.server.location.gnss.NtpTimeHelper.InjectNtpTimeCallback; +import com.android.server.location.gnss.hal.GnssNative; import com.android.server.location.injector.Injector; import com.android.server.location.provider.AbstractLocationProvider; @@ -96,8 +113,10 @@ import java.util.Set; * {@hide} */ public class GnssLocationProvider extends AbstractLocationProvider implements - InjectNtpTimeCallback, - GnssSatelliteBlocklistCallback { + InjectNtpTimeCallback, GnssSatelliteBlocklistCallback, GnssNative.BaseCallbacks, + GnssNative.LocationCallbacks, GnssNative.SvStatusCallbacks, GnssNative.AGpsCallbacks, + GnssNative.PsdsCallbacks, GnssNative.NotificationCallbacks, + GnssNative.LocationRequestCallbacks, GnssNative.TimeCallbacks { private static final String TAG = "GnssLocationProvider"; @@ -115,101 +134,17 @@ public class GnssLocationProvider extends AbstractLocationProvider implements ProviderProperties.POWER_USAGE_HIGH, ProviderProperties.ACCURACY_FINE); - // these need to match GnssPositionMode enum in IGnss.hal - private static final int GPS_POSITION_MODE_STANDALONE = 0; - private static final int GPS_POSITION_MODE_MS_BASED = 1; - private static final int GPS_POSITION_MODE_MS_ASSISTED = 2; - - // these need to match GnssPositionRecurrence enum in IGnss.hal - private static final int GPS_POSITION_RECURRENCE_PERIODIC = 0; - private static final int GPS_POSITION_RECURRENCE_SINGLE = 1; - - // these need to match GnssStatusValue enum in IGnssCallback.hal - private static final int GPS_STATUS_NONE = 0; - private static final int GPS_STATUS_SESSION_BEGIN = 1; - private static final int GPS_STATUS_SESSION_END = 2; - private static final int GPS_STATUS_ENGINE_ON = 3; - private static final int GPS_STATUS_ENGINE_OFF = 4; - - // these need to match GnssLocationFlags enum in types.hal - private static final int LOCATION_INVALID = 0; - private static final int LOCATION_HAS_LAT_LONG = 1; - private static final int LOCATION_HAS_ALTITUDE = 2; - private static final int LOCATION_HAS_SPEED = 4; - private static final int LOCATION_HAS_BEARING = 8; - private static final int LOCATION_HAS_HORIZONTAL_ACCURACY = 16; - private static final int LOCATION_HAS_VERTICAL_ACCURACY = 32; - private static final int LOCATION_HAS_SPEED_ACCURACY = 64; - private static final int LOCATION_HAS_BEARING_ACCURACY = 128; - - // these need to match ElapsedRealtimeFlags enum in types.hal - private static final int ELAPSED_REALTIME_HAS_TIMESTAMP_NS = 1; - private static final int ELAPSED_REALTIME_HAS_TIME_UNCERTAINTY_NS = 2; - - // IMPORTANT - the GPS_DELETE_* symbols here must match GnssAidingData enum in IGnss.hal - private static final int GPS_DELETE_EPHEMERIS = 0x0001; - private static final int GPS_DELETE_ALMANAC = 0x0002; - private static final int GPS_DELETE_POSITION = 0x0004; - private static final int GPS_DELETE_TIME = 0x0008; - private static final int GPS_DELETE_IONO = 0x0010; - private static final int GPS_DELETE_UTC = 0x0020; - private static final int GPS_DELETE_HEALTH = 0x0040; - private static final int GPS_DELETE_SVDIR = 0x0080; - private static final int GPS_DELETE_SVSTEER = 0x0100; - private static final int GPS_DELETE_SADATA = 0x0200; - private static final int GPS_DELETE_RTI = 0x0400; - private static final int GPS_DELETE_CELLDB_INFO = 0x8000; - private static final int GPS_DELETE_ALL = 0xFFFF; - - // The GPS_CAPABILITY_* flags must match Capabilities enum in IGnssCallback.hal - private static final int GPS_CAPABILITY_SCHEDULING = 0x0000001; - private static final int GPS_CAPABILITY_MSB = 0x0000002; - private static final int GPS_CAPABILITY_MSA = 0x0000004; - private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008; - private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010; - public static final int GPS_CAPABILITY_GEOFENCING = 0x0000020; - public static final int GPS_CAPABILITY_MEASUREMENTS = 0x0000040; - public static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080; - public static final int GPS_CAPABILITY_LOW_POWER_MODE = 0x0000100; - public static final int GPS_CAPABILITY_SATELLITE_BLOCKLIST = 0x0000200; - public static final int GPS_CAPABILITY_MEASUREMENT_CORRECTIONS = 0x0000400; - public static final int GPS_CAPABILITY_ANTENNA_INFO = 0x0000800; - // The AGPS SUPL mode private static final int AGPS_SUPL_MODE_MSA = 0x02; private static final int AGPS_SUPL_MODE_MSB = 0x01; + // handler messages private static final int INJECT_NTP_TIME = 5; - // PSDS stands for Predicted Satellite Data Service private static final int DOWNLOAD_PSDS_DATA = 6; private static final int REQUEST_LOCATION = 16; private static final int REPORT_LOCATION = 17; // HAL reports location private static final int REPORT_SV_STATUS = 18; // HAL reports SV status - // Request setid - private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1; - private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2; - - // ref. location info - private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1; - private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2; - - // set id info - private static final int AGPS_SETID_TYPE_NONE = 0; - private static final int AGPS_SETID_TYPE_IMSI = 1; - private static final int AGPS_SETID_TYPE_MSISDN = 2; - - private static final int GPS_GEOFENCE_UNAVAILABLE = 1 << 0L; - private static final int GPS_GEOFENCE_AVAILABLE = 1 << 1L; - - // GPS Geofence errors. Should match GeofenceStatus enum in IGnssGeofenceCallback.hal. - private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0; - private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100; - private static final int GPS_GEOFENCE_ERROR_ID_EXISTS = -101; - private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102; - private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103; - private static final int GPS_GEOFENCE_ERROR_GENERIC = -149; - // TCP/IP constants. // Valid TCP/UDP port range is (0, 65535]. private static final int TCP_MIN_PORT = 0; @@ -289,19 +224,13 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private static final long LOCATION_OFF_DELAY_THRESHOLD_WARN_MILLIS = 2 * 1000; private static final long LOCATION_OFF_DELAY_THRESHOLD_ERROR_MILLIS = 15 * 1000; - private static final String DOWNLOAD_EXTRA_WAKELOCK_KEY = "GnssLocationProviderPsdsDownload"; - - // Set lower than the current ITAR limit of 600m/s to allow this to trigger even if GPS HAL - // stops output right at 600m/s, depriving this of the information of a device that reaches - // greater than 600m/s, and higher than the speed of sound to avoid impacting most use cases. - private static final float ITAR_SPEED_LIMIT_METERS_PER_SECOND = 400.0F; - - private final Object mLock = new Object(); private final Context mContext; private final Handler mHandler; + private final GnssNative mGnssNative; + @GuardedBy("mLock") private final ExponentialBackOff mPsdsBackOff = new ExponentialBackOff(RETRY_INTERVAL, MAX_RETRY_INTERVAL); @@ -314,7 +243,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private boolean mBatchingEnabled; private boolean mShutdown; - private boolean mNavigating; private boolean mStarted; private boolean mBatchingStarted; private long mStartedChangedElapsedRealtime; @@ -334,9 +262,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private final WorkSource mClientSource = new WorkSource(); - // capabilities reported through the top level IGnssCallback.hal - private volatile int mTopHalCapabilities; - // true if PSDS is supported private boolean mSupportsPsds; @GuardedBy("mLock") @@ -357,15 +282,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private boolean mSuplEsEnabled = false; private final LocationExtras mLocationExtras = new LocationExtras(); - private final GnssStatusProvider mGnssStatusListenerHelper; - private final GnssMeasurementsProvider mGnssMeasurementsProvider; - private final GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider; - private final GnssAntennaInfoProvider mGnssAntennaInfoProvider; - private final GnssNavigationMessageProvider mGnssNavigationMessageProvider; - private final GnssPowerIndicationProvider mGnssPowerIndicationProvider; private final NtpTimeHelper mNtpTimeHelper; - private final GnssGeofenceProvider mGnssGeofenceProvider; - private final GnssCapabilitiesProvider mGnssCapabilitiesProvider; private final GnssSatelliteBlocklistHelper mGnssSatelliteBlocklistHelper; // Available only on GNSS HAL 2.0 implementations and later. @@ -384,44 +301,12 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private final AppOpsManager mAppOps; private final IBatteryStats mBatteryStats; - private GeofenceHardwareImpl mGeofenceHardwareImpl; - - // Volatile for simple inter-thread sync on these values. - private volatile int mHardwareYear = 0; - private volatile String mHardwareModelName; - - private volatile boolean mItarSpeedLimitExceeded = false; - @GuardedBy("mLock") private final ArrayList mFlushListeners = new ArrayList<>(0); // GNSS Metrics private final GnssMetrics mGnssMetrics; - public GnssStatusProvider getGnssStatusProvider() { - return mGnssStatusListenerHelper; - } - - public IGpsGeofenceHardware getGpsGeofenceProxy() { - return mGnssGeofenceProvider; - } - - public GnssMeasurementsProvider getGnssMeasurementsProvider() { - return mGnssMeasurementsProvider; - } - - public GnssMeasurementCorrectionsProvider getGnssMeasurementCorrectionsProvider() { - return mGnssMeasurementCorrectionsProvider; - } - - public GnssAntennaInfoProvider getGnssAntennaInfoProvider() { - return mGnssAntennaInfoProvider; - } - - public GnssNavigationMessageProvider getGnssNavigationMessageProvider() { - return mGnssNavigationMessageProvider; - } - /** * Implements {@link GnssSatelliteBlocklistCallback#onUpdateSatelliteBlocklist}. */ @@ -485,20 +370,23 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } } - public GnssLocationProvider(Context context, Injector injector) { + public GnssLocationProvider(Context context, Injector injector, GnssNative gnssNative, + GnssMetrics gnssMetrics) { super(FgThread.getExecutor(), CallerIdentity.fromContext(context), PROPERTIES); mContext = context; + mGnssNative = gnssNative; + mGnssMetrics = gnssMetrics; // Create a wake lock PowerManager powerManager = Objects.requireNonNull( mContext.getSystemService(PowerManager.class)); - mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); + mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*location*:" + TAG); mWakeLock.setReferenceCounted(true); // Create a separate wake lock for psds downloader as it may be released due to timeout. mDownloadPsdsWakeLock = powerManager.newWakeLock( - PowerManager.PARTIAL_WAKE_LOCK, DOWNLOAD_EXTRA_WAKELOCK_KEY); + PowerManager.PARTIAL_WAKE_LOCK, "*location*:PsdsDownload"); mDownloadPsdsWakeLock.setReferenceCounted(true); mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); @@ -518,8 +406,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements // relative long time, so the ctor() is kept to create objects needed by this instance, // while IO initialization and registration is delegated to our internal handler // this approach is just fine because events are posted to our handler anyway - mGnssConfiguration = new GnssConfiguration(mContext); - mGnssCapabilitiesProvider = new GnssCapabilitiesProvider(); + mGnssConfiguration = mGnssNative.getConfiguration(); // Create a GPS net-initiated handler (also needed by handleInitialize) mNIHandler = new GpsNetInitiatedHandler(context, mNetInitiatedListener, @@ -529,21 +416,21 @@ public class GnssLocationProvider extends AbstractLocationProvider implements mNetworkConnectivityHandler = new GnssNetworkConnectivityHandler(context, GnssLocationProvider.this::onNetworkAvailable, mHandler.getLooper(), mNIHandler); - mGnssStatusListenerHelper = new GnssStatusProvider(injector); - mGnssMeasurementsProvider = new GnssMeasurementsProvider(injector); - mGnssMeasurementCorrectionsProvider = new GnssMeasurementCorrectionsProvider(mHandler); - mGnssAntennaInfoProvider = new GnssAntennaInfoProvider(injector); - mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(injector); - mGnssPowerIndicationProvider = new GnssPowerIndicationProvider(); - - mGnssMetrics = new GnssMetrics(mContext, mBatteryStats); mNtpTimeHelper = new NtpTimeHelper(mContext, mHandler.getLooper(), this); mGnssSatelliteBlocklistHelper = new GnssSatelliteBlocklistHelper(mContext, mHandler.getLooper(), this); - mGnssGeofenceProvider = new GnssGeofenceProvider(); setAllowed(true); + + mGnssNative.addBaseCallbacks(this); + mGnssNative.addLocationCallbacks(this); + mGnssNative.addSvStatusCallbacks(this); + mGnssNative.setAGpsCallbacks(this); + mGnssNative.setPsdsCallbacks(this); + mGnssNative.setNotificationCallbacks(this); + mGnssNative.setLocationRequestCallbacks(this); + mGnssNative.setTimeCallbacks(this); } /** Called when system is ready. */ @@ -573,12 +460,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } private void handleInitialize() { - // it *appears* that native_init() needs to be called at least once before invoking any - // other gnss methods, so we cycle once on initialization. - native_init(); - native_cleanup(); - - if (native_is_gnss_visibility_control_supported()) { + if (mGnssNative.isGnssVisibilityControlSupported()) { mGnssVisibilityControl = new GnssVisibilityControl(mContext, mHandler.getLooper(), mNIHandler); } @@ -633,7 +515,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements */ @Override public void injectTime(long time, long timeReference, int uncertainty) { - native_inject_time(time, timeReference, uncertainty); + mGnssNative.injectTime(time, timeReference, uncertainty); } /** @@ -645,7 +527,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements if (mSupportsPsds) { synchronized (mLock) { for (int psdsType : mPendingDownloadPsdsTypes) { - downloadPsdsData(psdsType); + sendMessage(DOWNLOAD_PSDS_DATA, psdsType, null); } mPendingDownloadPsdsTypes.clear(); } @@ -722,38 +604,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements return; } - 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(); - - int elapsedRealtimeFlags = ELAPSED_REALTIME_HAS_TIMESTAMP_NS - | (location.hasElapsedRealtimeUncertaintyNanos() - ? ELAPSED_REALTIME_HAS_TIME_UNCERTAINTY_NS : 0); - long elapsedRealtimeNanos = location.getElapsedRealtimeNanos(); - double elapsedRealtimeUncertaintyNanos = location.getElapsedRealtimeUncertaintyNanos(); - - native_inject_best_location( - gnssLocationFlags, latitudeDegrees, longitudeDegrees, - altitudeMeters, speedMetersPerSec, bearingDegrees, - horizontalAccuracyMeters, verticalAccuracyMeters, - speedAccuracyMetersPerSecond, bearingAccuracyDegrees, timestamp, - elapsedRealtimeFlags, elapsedRealtimeNanos, elapsedRealtimeUncertaintyNanos); + mGnssNative.injectBestLocation(location); } /** Returns true if the location request is too frequent. */ @@ -787,7 +638,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements if (data != null) { mHandler.post(() -> { if (DEBUG) Log.d(TAG, "calling native_inject_psds_data"); - native_inject_psds_data(data, data.length, psdsType); + mGnssNative.injectPsdsData(data, data.length, psdsType); synchronized (mLock) { mPsdsBackOff.reset(); } @@ -822,9 +673,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } private void injectLocation(Location location) { - if (location.hasAccuracy() && !location.isFromMockProvider()) { - native_inject_location(location.getLatitude(), location.getLongitude(), - location.getAccuracy()); + if (!location.isFromMockProvider()) { + mGnssNative.injectLocation(location); } } @@ -834,7 +684,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements if (mSuplServerHost != null && mSuplServerPort > TCP_MIN_PORT && mSuplServerPort <= TCP_MAX_PORT) { - native_set_agps_server(GnssNetworkConnectivityHandler.AGPS_TYPE_SUPL, + mGnssNative.setAgpsServer(GnssNetworkConnectivityHandler.AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort); } } @@ -850,16 +700,16 @@ public class GnssLocationProvider extends AbstractLocationProvider implements if (agpsEnabled) { int suplMode = mGnssConfiguration.getSuplMode(0); if (suplMode == 0) { - return GPS_POSITION_MODE_STANDALONE; + return GNSS_POSITION_MODE_STANDALONE; } // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor // such mode when it is available - if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) { - return GPS_POSITION_MODE_MS_BASED; + if (mGnssNative.getCapabilities().hasMsb() && (suplMode & AGPS_SUPL_MODE_MSB) != 0) { + return GNSS_POSITION_MODE_MS_BASED; } } - return GPS_POSITION_MODE_STANDALONE; + return GNSS_POSITION_MODE_STANDALONE; } private void setGpsEnabled(boolean enabled) { @@ -871,23 +721,23 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private void handleEnable() { if (DEBUG) Log.d(TAG, "handleEnable"); - boolean inited = native_init(); + boolean inited = mGnssNative.init(); if (inited) { setGpsEnabled(true); - mSupportsPsds = native_supports_psds(); + mSupportsPsds = mGnssNative.isPsdsSupported(); // TODO: remove the following native calls if we can make sure they are redundant. if (mSuplServerHost != null) { - native_set_agps_server(GnssNetworkConnectivityHandler.AGPS_TYPE_SUPL, + mGnssNative.setAgpsServer(GnssNetworkConnectivityHandler.AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort); } if (mC2KServerHost != null) { - native_set_agps_server(GnssNetworkConnectivityHandler.AGPS_TYPE_C2K, + mGnssNative.setAgpsServer(GnssNetworkConnectivityHandler.AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort); } - mBatchingEnabled = native_init_batching() && native_get_batch_size() > 1; + mBatchingEnabled = mGnssNative.initBatching() && mGnssNative.getBatchSize() > 1; if (mGnssVisibilityControl != null) { mGnssVisibilityControl.onGpsEnabledChanged(/* isEnabled= */ true); } @@ -909,8 +759,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements mGnssVisibilityControl.onGpsEnabledChanged(/* isEnabled= */ false); } // do this before releasing wakelock - native_cleanup_batching(); - native_cleanup(); + mGnssNative.cleanupBatching(); + mGnssNative.cleanup(); } private void updateEnabled() { @@ -949,7 +799,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements * minimum size guaranteed to be available for batching operations. */ public int getBatchSize() { - return native_get_batch_size(); + return mGnssNative.getBatchSize(); } @Override @@ -963,7 +813,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements if (!added) { listener.run(); } else { - native_flush_batch(); + mGnssNative.flushBatch(); } } @@ -1007,9 +857,9 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } else { stopBatching(); - if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) { + if (mStarted && mGnssNative.getCapabilities().hasScheduling()) { // change period and/or lowPowerMode - if (!setPositionMode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC, + if (!setPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC, mFixInterval, mProviderRequest.isLowPower())) { Log.e(TAG, "set_position_mode failed in updateRequirements"); } @@ -1043,8 +893,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements return true; } - boolean result = native_set_position_mode(mode, recurrence, minInterval, - 0, 0, lowPowerMode); + boolean result = mGnssNative.setPositionMode(mode, recurrence, minInterval, 0, 0, + lowPowerMode); if (result) { mLastPositionMode = positionMode; } else { @@ -1123,11 +973,11 @@ public class GnssLocationProvider extends AbstractLocationProvider implements requestUtcTime(); } else if ("force_psds_injection".equals(command)) { if (mSupportsPsds) { - downloadPsdsData(/* psdsType= */ - GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX); + sendMessage(DOWNLOAD_PSDS_DATA, GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX, + null); } } else if ("request_power_stats".equals(command)) { - GnssPowerIndicationProvider.requestPowerStats(); + mGnssNative.requestPowerStats(); } else { Log.w(TAG, "sendExtraCommand: unknown command " + command); } @@ -1137,26 +987,26 @@ public class GnssLocationProvider extends AbstractLocationProvider implements int flags; if (extras == null) { - flags = GPS_DELETE_ALL; + flags = GNSS_AIDING_TYPE_ALL; } else { flags = 0; - if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS; - if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC; - if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION; - if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME; - if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO; - if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC; - if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH; - if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR; - if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER; - if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA; - if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI; - if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO; - if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL; + if (extras.getBoolean("ephemeris")) flags |= GNSS_AIDING_TYPE_EPHEMERIS; + if (extras.getBoolean("almanac")) flags |= GNSS_AIDING_TYPE_ALMANAC; + if (extras.getBoolean("position")) flags |= GNSS_AIDING_TYPE_POSITION; + if (extras.getBoolean("time")) flags |= GNSS_AIDING_TYPE_TIME; + if (extras.getBoolean("iono")) flags |= GNSS_AIDING_TYPE_IONO; + if (extras.getBoolean("utc")) flags |= GNSS_AIDING_TYPE_UTC; + if (extras.getBoolean("health")) flags |= GNSS_AIDING_TYPE_HEALTH; + if (extras.getBoolean("svdir")) flags |= GNSS_AIDING_TYPE_SVDIR; + if (extras.getBoolean("svsteer")) flags |= GNSS_AIDING_TYPE_SVSTEER; + if (extras.getBoolean("sadata")) flags |= GNSS_AIDING_TYPE_SADATA; + if (extras.getBoolean("rti")) flags |= GNSS_AIDING_TYPE_RTI; + if (extras.getBoolean("celldb-info")) flags |= GNSS_AIDING_TYPE_CELLDB_INFO; + if (extras.getBoolean("all")) flags |= GNSS_AIDING_TYPE_ALL; } if (flags != 0) { - native_delete_aiding_data(flags); + mGnssNative.deleteAidingData(flags); } } @@ -1166,13 +1016,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements mTimeToFirstFix = 0; mLastFixTime = 0; setStarted(true); - mPositionMode = GPS_POSITION_MODE_STANDALONE; - // Notify about suppressed output, if speed limit was previously exceeded. - // Elsewhere, we check again with every speed output reported. - if (mItarSpeedLimitExceeded) { - Log.i(TAG, "startNavigating with ITAR limit in place. Output limited " - + "until slow enough speed reported."); - } + mPositionMode = GNSS_POSITION_MODE_STANDALONE; boolean agpsEnabled = (Settings.Global.getInt(mContext.getContentResolver(), @@ -1183,13 +1027,13 @@ public class GnssLocationProvider extends AbstractLocationProvider implements String mode; switch (mPositionMode) { - case GPS_POSITION_MODE_STANDALONE: + case GNSS_POSITION_MODE_STANDALONE: mode = "standalone"; break; - case GPS_POSITION_MODE_MS_ASSISTED: + case GNSS_POSITION_MODE_MS_ASSISTED: mode = "MS_ASSISTED"; break; - case GPS_POSITION_MODE_MS_BASED: + case GNSS_POSITION_MODE_MS_BASED: mode = "MS_BASED"; break; default: @@ -1199,14 +1043,14 @@ public class GnssLocationProvider extends AbstractLocationProvider implements Log.d(TAG, "setting position_mode to " + mode); } - int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000); - if (!setPositionMode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC, + int interval = mGnssNative.getCapabilities().hasScheduling() ? mFixInterval : 1000; + if (!setPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC, interval, mProviderRequest.isLowPower())) { setStarted(false); Log.e(TAG, "set_position_mode failed in startNavigating()"); return; } - if (!native_start()) { + if (!mGnssNative.start()) { setStarted(false); Log.e(TAG, "native_start failed in startNavigating()"); return; @@ -1215,7 +1059,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements // reset SV count to zero mLocationExtras.reset(); mFixRequestTime = SystemClock.elapsedRealtime(); - if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) { + if (!mGnssNative.getCapabilities().hasScheduling()) { // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT // and our fix interval is not short if (mFixInterval >= NO_FIX_TIMEOUT) { @@ -1231,7 +1075,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements if (DEBUG) Log.d(TAG, "stopNavigating"); if (mStarted) { setStarted(false); - native_stop(); + mGnssNative.stop(); mLastFixTime = 0; // native_stop() may reset the position mode in hardware. mLastPositionMode = null; @@ -1247,7 +1091,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements if (DEBUG) { Log.d(TAG, "startBatching " + mFixInterval); } - if (native_start_batch(MILLISECONDS.toNanos(mFixInterval), true)) { + if (mGnssNative.startBatch(MILLISECONDS.toNanos(mFixInterval), true)) { mBatchingStarted = true; } else { Log.e(TAG, "native_start_batch failed in startBatching()"); @@ -1257,7 +1101,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private void stopBatching() { if (DEBUG) Log.d(TAG, "stopBatching"); if (mBatchingStarted) { - native_stop_batch(); + mGnssNative.stopBatch(); mBatchingStarted = false; } } @@ -1277,28 +1121,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements mWakeupListener, mHandler); } - private boolean hasCapability(int capability) { - return (mTopHalCapabilities & capability) != 0; - } - - void reportLocation(boolean hasLatLong, Location location) { - sendMessage(REPORT_LOCATION, hasLatLong ? 1 : 0, location); - } - private void handleReportLocation(boolean hasLatLong, Location location) { - if (location.hasSpeed()) { - mItarSpeedLimitExceeded = location.getSpeed() > ITAR_SPEED_LIMIT_METERS_PER_SECOND; - } - - if (mItarSpeedLimitExceeded) { - Log.i(TAG, "Hal reported a speed in excess of ITAR limit." - + " GPS/GNSS Navigation output blocked."); - if (mStarted) { - mGnssMetrics.logReceivedLocationStatus(false); - } - return; // No output of location allowed - } - if (VERBOSE) Log.v(TAG, "reportLocation " + location.toString()); location.setExtras(mLocationExtras.getBundle()); @@ -1341,9 +1164,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements if (mStarted) { mGnssMetrics.logTimeToFirstFixMilliSecs(mTimeToFirstFix); } - - // notify status listeners - mGnssStatusListenerHelper.onFirstFix(mTimeToFirstFix); } if (mStarted) { @@ -1351,51 +1171,19 @@ public class GnssLocationProvider extends AbstractLocationProvider implements // spend too much power searching for a location, when the requested update rate is // slow. // As we just recievied a location, we'll cancel that timer. - if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) { + if (!mGnssNative.getCapabilities().hasScheduling() && mFixInterval < NO_FIX_TIMEOUT) { mAlarmManager.cancel(mTimeoutListener); } } - if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted + if (!mGnssNative.getCapabilities().hasScheduling() && mStarted && mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) { if (DEBUG) Log.d(TAG, "got fix, hibernating"); hibernate(); } } - void reportStatus(int status) { - if (DEBUG) Log.v(TAG, "reportStatus status: " + status); - - boolean wasNavigating = mNavigating; - switch (status) { - case GPS_STATUS_SESSION_BEGIN: - mNavigating = true; - break; - case GPS_STATUS_ENGINE_ON: - break; - case GPS_STATUS_SESSION_END: - // fall through - case GPS_STATUS_ENGINE_OFF: - mNavigating = false; - break; - } - - if (wasNavigating != mNavigating) { - mGnssStatusListenerHelper.onStatusChanged(mNavigating); - } - } - - void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0DbHzs, - float[] elevations, float[] azimuths, float[] carrierFrequencies, - float[] basebandCn0DbHzs) { - sendMessage(REPORT_SV_STATUS, 0, - GnssStatus.wrap(svCount, svidWithFlags, cn0DbHzs, elevations, azimuths, - carrierFrequencies, basebandCn0DbHzs)); - } - private void handleReportSvStatus(GnssStatus gnssStatus) { - mGnssStatusListenerHelper.onSvStatusChanged(gnssStatus); - // Log CN0 as part of GNSS metrics mGnssMetrics.logCn0(gnssStatus); @@ -1425,289 +1213,12 @@ public class GnssLocationProvider extends AbstractLocationProvider implements mGnssMetrics.logSvStatus(gnssStatus); } - void reportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) { - mNetworkConnectivityHandler.onReportAGpsStatus(agpsType, agpsStatus, suplIpAddr); - } - - void reportNmea(long timestamp) { - if (!mItarSpeedLimitExceeded) { - int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length); - String nmea = new String(mNmeaBuffer, 0 /* offset */, length); - mGnssStatusListenerHelper.onNmeaReceived(timestamp, nmea); - } - } - - void reportMeasurementData(GnssMeasurementsEvent event) { - if (!mItarSpeedLimitExceeded) { - // send to handler to allow native to return quickly - mHandler.post(() -> mGnssMeasurementsProvider.onMeasurementsAvailable(event)); - } - } - - void reportAntennaInfo(List antennaInfos) { - mHandler.post(() -> mGnssAntennaInfoProvider.onGnssAntennaInfoAvailable(antennaInfos)); - } - - void reportNavigationMessage(GnssNavigationMessage event) { - if (!mItarSpeedLimitExceeded) { - // send to handler to allow native to return quickly - mHandler.post(() -> mGnssNavigationMessageProvider.onNavigationMessageAvailable(event)); - } - } - - void reportGnssPowerStats(GnssPowerStats powerStats) { - mHandler.post(() -> mGnssPowerIndicationProvider.onGnssPowerStatsAvailable(powerStats)); - } - - void setTopHalCapabilities(int topHalCapabilities) { - mHandler.post(() -> { - mTopHalCapabilities = topHalCapabilities; - - if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) { - mNtpTimeHelper.enablePeriodicTimeInjection(); - requestUtcTime(); - } - - restartRequests(); - - mGnssCapabilitiesProvider.setTopHalCapabilities(mTopHalCapabilities); - }); - } - - void setSubHalMeasurementCorrectionsCapabilities(int subHalCapabilities) { - mHandler.post(() -> { - if (!mGnssMeasurementCorrectionsProvider.onCapabilitiesUpdated(subHalCapabilities)) { - return; - } - - mGnssCapabilitiesProvider.setSubHalMeasurementCorrectionsCapabilities( - subHalCapabilities); - }); - } - - /** - * Sets the capabilities bits for IGnssPowerIndication HAL. - * - * These capabilities are defined in IGnssPowerIndicationCallback.aidl. - */ - void setSubHalPowerIndicationCapabilities(int subHalCapabilities) { - mHandler.post(() -> mGnssPowerIndicationProvider.onCapabilitiesUpdated(subHalCapabilities)); - } - - private void restartRequests() { - Log.i(TAG, "restartRequests"); - - restartLocationRequest(); - mGnssGeofenceProvider.resumeIfStarted(); - } - private void restartLocationRequest() { if (DEBUG) Log.d(TAG, "restartLocationRequest"); setStarted(false); updateRequirements(); } - void setGnssYearOfHardware(final int yearOfHardware) { - // mHardwareYear is simply set here, to be read elsewhere, and is volatile for safe sync - if (DEBUG) Log.d(TAG, "setGnssYearOfHardware called with " + yearOfHardware); - mHardwareYear = yearOfHardware; - } - - void setGnssHardwareModelName(final String modelName) { - // mHardwareModelName is simply set here, to be read elsewhere, and volatile for safe sync - if (DEBUG) Log.d(TAG, "setGnssModelName called with " + modelName); - mHardwareModelName = modelName; - } - - void reportGnssServiceRestarted() { - if (DEBUG) Log.d(TAG, "reportGnssServiceDied"); - - // it *appears* that native_init() needs to be called at least once before invoking any - // other gnss methods, so we cycle once on initialization. - native_init(); - native_cleanup(); - - // resend configuration into the restarted HAL service. - reloadGpsProperties(); - if (isGpsEnabled()) { - setGpsEnabled(false); - updateEnabled(); - } - } - - /** - * Interface for GnssSystemInfo methods. - */ - public interface GnssSystemInfoProvider { - /** - * Returns the year of underlying GPS hardware. - */ - int getGnssYearOfHardware(); - - /** - * Returns the model name of underlying GPS hardware. - */ - String getGnssHardwareModelName(); - } - - /** - * @hide - */ - public GnssSystemInfoProvider getGnssSystemInfoProvider() { - return new GnssSystemInfoProvider() { - @Override - public int getGnssYearOfHardware() { - return mHardwareYear; - } - - @Override - public String getGnssHardwareModelName() { - return mHardwareModelName; - } - }; - } - - /** - * Interface for GnssMetrics methods. - */ - public interface GnssMetricsProvider { - /** - * Returns GNSS metrics as proto string - */ - String getGnssMetricsAsProtoString(); - } - - /** - * @hide - */ - public GnssMetricsProvider getGnssMetricsProvider() { - return mGnssMetrics::dumpGnssMetricsAsProtoString; - } - - /** - * @hide - */ - public GnssCapabilitiesProvider getGnssCapabilitiesProvider() { - return mGnssCapabilitiesProvider; - } - - void reportLocationBatch(Location[] locations) { - if (DEBUG) { - Log.d(TAG, "Location batch of size " + locations.length + " reported"); - } - - Runnable[] listeners; - synchronized (mLock) { - listeners = mFlushListeners.toArray(new Runnable[0]); - mFlushListeners.clear(); - } - - if (locations.length > 0) { - reportLocation(LocationResult.create(Arrays.asList(locations)).validate()); - } - - for (Runnable listener : listeners) { - listener.run(); - } - } - - void downloadPsdsData(int psdsType) { - if (DEBUG) Log.d(TAG, "downloadPsdsData. psdsType: " + psdsType); - sendMessage(DOWNLOAD_PSDS_DATA, psdsType, null); - } - - /** - * Converts the GPS HAL status to the internal Geofence Hardware status. - */ - private static int getGeofenceStatus(int status) { - switch (status) { - case GPS_GEOFENCE_OPERATION_SUCCESS: - return GeofenceHardware.GEOFENCE_SUCCESS; - case GPS_GEOFENCE_ERROR_GENERIC: - return GeofenceHardware.GEOFENCE_FAILURE; - case GPS_GEOFENCE_ERROR_ID_EXISTS: - return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS; - case GPS_GEOFENCE_ERROR_INVALID_TRANSITION: - return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION; - case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES: - return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES; - case GPS_GEOFENCE_ERROR_ID_UNKNOWN: - return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN; - default: - return -1; - } - } - - void reportGeofenceTransition(int geofenceId, Location location, int transition, - long transitionTimestamp) { - mHandler.post(() -> { - if (mGeofenceHardwareImpl == null) { - mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); - } - - mGeofenceHardwareImpl.reportGeofenceTransition( - geofenceId, - location, - transition, - transitionTimestamp, - GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, - FusedBatchOptions.SourceTechnologies.GNSS); - }); - } - - void reportGeofenceStatus(int status, Location location) { - mHandler.post(() -> { - if (mGeofenceHardwareImpl == null) { - mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); - } - int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE; - if (status == GPS_GEOFENCE_AVAILABLE) { - monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE; - } - mGeofenceHardwareImpl.reportGeofenceMonitorStatus( - GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, - monitorStatus, - location, - FusedBatchOptions.SourceTechnologies.GNSS); - }); - } - - void reportGeofenceAddStatus(int geofenceId, int status) { - mHandler.post(() -> { - if (mGeofenceHardwareImpl == null) { - mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); - } - mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status)); - }); - } - - void reportGeofenceRemoveStatus(int geofenceId, int status) { - mHandler.post(() -> { - if (mGeofenceHardwareImpl == null) { - mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); - } - mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status)); - }); - } - - void reportGeofencePauseStatus(int geofenceId, int status) { - mHandler.post(() -> { - if (mGeofenceHardwareImpl == null) { - mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); - } - mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status)); - }); - } - - void reportGeofenceResumeStatus(int geofenceId, int status) { - mHandler.post(() -> { - if (mGeofenceHardwareImpl == null) { - mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); - } - mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status)); - }); - } - //============================================================= // NI Client support //============================================================= @@ -1721,7 +1232,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements Log.d(TAG, "sendNiResponse, notifId: " + notificationId + ", response: " + userResponse); } - native_send_ni_response(notificationId, userResponse); + mGnssNative.sendNiResponse(notificationId, userResponse); FrameworkStatsLog.write(FrameworkStatsLog.GNSS_NI_EVENT_REPORTED, FrameworkStatsLog.GNSS_NI_EVENT_REPORTED__EVENT_TYPE__NI_RESPONSE, @@ -1749,7 +1260,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } /** Reports a NI notification. */ - void reportNiNotification(int notificationId, int niType, int notifyFlags, int timeout, + private void reportNiNotification(int notificationId, int niType, int notifyFlags, int timeout, int defaultResponse, String requestorId, String text, int requestorIdEncoding, int textEncoding) { Log.i(TAG, "reportNiNotification: entered"); @@ -1798,52 +1309,12 @@ public class GnssLocationProvider extends AbstractLocationProvider implements /* userResponse= */ 0); } - /** - * We should be careful about receiving null string from the TelephonyManager, - * because sending null String to JNI function would cause a crash. - */ - void requestSetID(int flags) { - TelephonyManager phone = (TelephonyManager) - mContext.getSystemService(Context.TELEPHONY_SERVICE); - int type = AGPS_SETID_TYPE_NONE; - String setId = null; - - int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId(); - if (SubscriptionManager.isValidSubscriptionId(ddSubId)) { - phone = phone.createForSubscriptionId(ddSubId); - } - if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) { - setId = phone.getSubscriberId(); - if (setId != null) { - // This means the framework has the SIM card. - type = AGPS_SETID_TYPE_IMSI; - } - } else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) { - setId = phone.getLine1Number(); - if (setId != null) { - // This means the framework has the SIM card. - type = AGPS_SETID_TYPE_MSISDN; - } - } - - native_agps_set_id(type, (setId == null) ? "" : setId); - } - - void requestLocation(boolean independentFromGnss, boolean isUserEmergency) { - if (DEBUG) { - Log.d(TAG, "requestLocation. independentFromGnss: " + independentFromGnss - + ", isUserEmergency: " - + isUserEmergency); - } - sendMessage(REQUEST_LOCATION, independentFromGnss ? 1 : 0, isUserEmergency); - } - - void requestUtcTime() { + private void requestUtcTime() { if (DEBUG) Log.d(TAG, "utcTimeRequest"); sendMessage(INJECT_NTP_TIME, 0, null); } - void requestRefLocation() { + private void requestRefLocation() { TelephonyManager phone = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); final int phoneType = phone.getPhoneType(); @@ -1864,8 +1335,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } else { type = AGPS_REF_LOCATION_TYPE_GSM_CELLID; } - native_agps_set_ref_location_cellid(type, mcc, mnc, - gsm_cell.getLac(), gsm_cell.getCid()); + mGnssNative.setAgpsReferenceLocationCellId(type, mcc, mnc, gsm_cell.getLac(), + gsm_cell.getCid()); } else { Log.e(TAG, "Error getting cell location info."); } @@ -1874,21 +1345,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } } - // Implements method nfwNotifyCb() in IGnssVisibilityControlCallback.hal. - void reportNfwNotification(String proxyAppPackageName, byte protocolStack, - String otherProtocolStackName, byte requestor, String requestorId, byte responseType, - boolean inEmergencyMode, boolean isCachedLocation) { - if (mGnssVisibilityControl == null) { - Log.e(TAG, "reportNfwNotification: mGnssVisibilityControl is not initialized."); - return; - } - - mGnssVisibilityControl.reportNfwNotification(proxyAppPackageName, protocolStack, - otherProtocolStackName, requestor, requestorId, responseType, inEmergencyMode, - isCachedLocation); - } - - // Implements method isInEmergencySession() in IGnssVisibilityControlCallback.hal. boolean isInEmergencySession() { return mNIHandler.getInEmergency(); } @@ -1986,97 +1442,143 @@ public class GnssLocationProvider extends AbstractLocationProvider implements pw.println("mBatchingStarted=" + mBatchingStarted); pw.println("mBatchSize=" + getBatchSize()); pw.println("mFixInterval=" + mFixInterval); - mGnssPowerIndicationProvider.dump(fd, pw, args); - pw.print("mTopHalCapabilities=0x" + Integer.toHexString(mTopHalCapabilities) + " ( "); - if (hasCapability(GPS_CAPABILITY_SCHEDULING)) pw.print("SCHEDULING "); - if (hasCapability(GPS_CAPABILITY_MSB)) pw.print("MSB "); - if (hasCapability(GPS_CAPABILITY_MSA)) pw.print("MSA "); - if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) pw.print("SINGLE_SHOT "); - if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) pw.print("ON_DEMAND_TIME "); - if (hasCapability(GPS_CAPABILITY_GEOFENCING)) pw.print("GEOFENCING "); - if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) pw.print("MEASUREMENTS "); - if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) pw.print("NAV_MESSAGES "); - if (hasCapability(GPS_CAPABILITY_LOW_POWER_MODE)) pw.print("LOW_POWER_MODE "); - if (hasCapability(GPS_CAPABILITY_SATELLITE_BLOCKLIST)) pw.print("SATELLITE_BLOCKLIST "); - if (hasCapability(GPS_CAPABILITY_MEASUREMENT_CORRECTIONS)) { - pw.print("MEASUREMENT_CORRECTIONS "); - } - if (hasCapability(GPS_CAPABILITY_ANTENNA_INFO)) pw.print("ANTENNA_INFO "); - pw.println(")"); - if (hasCapability(GPS_CAPABILITY_MEASUREMENT_CORRECTIONS)) { - pw.println("SubHal=MEASUREMENT_CORRECTIONS[" - + mGnssMeasurementCorrectionsProvider.toStringCapabilities() + "]"); - } pw.print(mGnssMetrics.dumpGnssMetricsAsText()); if (dumpAll) { pw.println("native internal state: "); - pw.println(" " + native_get_internal_state()); + pw.println(" " + mGnssNative.getInternalState()); } } - // preallocated to avoid memory allocation in reportNmea() - private final byte[] mNmeaBuffer = new byte[120]; + @Override + public void onHalRestarted() { + reloadGpsProperties(); + if (isGpsEnabled()) { + setGpsEnabled(false); + updateEnabled(); + } + } - private static native boolean native_is_gnss_visibility_control_supported(); + @Override + public void onCapabilitiesChanged(GnssCapabilities oldCapabilities, + GnssCapabilities newCapabilities) { + mHandler.post(() -> { + if (mGnssNative.getCapabilities().hasOnDemandTime()) { + mNtpTimeHelper.enablePeriodicTimeInjection(); + requestUtcTime(); + } - private native boolean native_init(); + restartLocationRequest(); + }); + } - private native void native_cleanup(); + @Override + public void onReportLocation(boolean hasLatLong, Location location) { + sendMessage(REPORT_LOCATION, hasLatLong ? 1 : 0, location); + } - private native boolean native_set_position_mode(int mode, int recurrence, int minInterval, - int preferredAccuracy, int preferredTime, boolean lowPowerMode); + @Override + public void onReportLocations(Location[] locations) { + if (DEBUG) { + Log.d(TAG, "Location batch of size " + locations.length + " reported"); + } - private native boolean native_start(); + Runnable[] listeners; + synchronized (mLock) { + listeners = mFlushListeners.toArray(new Runnable[0]); + mFlushListeners.clear(); + } - private native boolean native_stop(); + if (locations.length > 0) { + reportLocation(LocationResult.create(Arrays.asList(locations)).validate()); + } - private native void native_delete_aiding_data(int flags); + for (Runnable listener : listeners) { + listener.run(); + } + } - private native int native_read_nmea(byte[] buffer, int bufferSize); + @Override + public void onReportSvStatus(GnssStatus gnssStatus) { + sendMessage(REPORT_SV_STATUS, 0, gnssStatus); + } - 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, int elapsedRealtimeFlags, long elapsedRealtimeNanos, - double elapsedRealtimeUncertaintyNanos); + @Override + public void onReportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) { + mNetworkConnectivityHandler.onReportAGpsStatus(agpsType, agpsStatus, suplIpAddr); + } - private native void native_inject_location(double latitude, double longitude, float accuracy); + @Override + public void onRequestPsdsDownload(int psdsType) { + sendMessage(DOWNLOAD_PSDS_DATA, psdsType, null); + } - // PSDS Support - private native void native_inject_time(long time, long timeReference, int uncertainty); + @Override + public void onReportNiNotification(int notificationId, int niType, int notifyFlags, + int timeout, int defaultResponse, String requestorId, String text, + int requestorIdEncoding, int textEncoding) { + reportNiNotification(notificationId, niType, notifyFlags, timeout, + defaultResponse, requestorId, text, requestorIdEncoding, textEncoding); + } - private native boolean native_supports_psds(); + @Override + public void onRequestSetID(@GnssNative.AGpsCallbacks.AgpsSetIdFlags int flags) { + TelephonyManager phone = (TelephonyManager) + mContext.getSystemService(Context.TELEPHONY_SERVICE); + int type = AGPS_SETID_TYPE_NONE; + String setId = null; - private native void native_inject_psds_data(byte[] data, int length, int psdsType); + int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId(); + if (SubscriptionManager.isValidSubscriptionId(ddSubId)) { + phone = phone.createForSubscriptionId(ddSubId); + } + if ((flags & AGPS_REQUEST_SETID_IMSI) == AGPS_REQUEST_SETID_IMSI) { + setId = phone.getSubscriberId(); + if (setId != null) { + // This means the framework has the SIM card. + type = AGPS_SETID_TYPE_IMSI; + } + } else if ((flags & AGPS_REQUEST_SETID_MSISDN) == AGPS_REQUEST_SETID_MSISDN) { + setId = phone.getLine1Number(); + if (setId != null) { + // This means the framework has the SIM card. + type = AGPS_SETID_TYPE_MSISDN; + } + } - // DEBUG Support - private native String native_get_internal_state(); + mGnssNative.setAgpsSetId(type, (setId == null) ? "" : setId); + } - // AGPS Support - private native void native_agps_ni_message(byte[] msg, int length); + @Override + public void onRequestLocation(boolean independentFromGnss, boolean isUserEmergency) { + if (DEBUG) { + Log.d(TAG, "requestLocation. independentFromGnss: " + independentFromGnss + + ", isUserEmergency: " + + isUserEmergency); + } + sendMessage(REQUEST_LOCATION, independentFromGnss ? 1 : 0, isUserEmergency); + } - private native void native_set_agps_server(int type, String hostname, int port); + @Override + public void onRequestUtcTime() { + requestUtcTime(); + } - // Network-initiated (NI) Support - private native void native_send_ni_response(int notificationId, int userResponse); + @Override + public void onRequestRefLocation() { + requestRefLocation(); + } - // AGPS ril support - private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc, - int lac, int cid); + @Override + public void onReportNfwNotification(String proxyAppPackageName, byte protocolStack, + String otherProtocolStackName, byte requestor, String requestorId, + byte responseType, boolean inEmergencyMode, boolean isCachedLocation) { + if (mGnssVisibilityControl == null) { + Log.e(TAG, "reportNfwNotification: mGnssVisibilityControl uninitialized."); + return; + } - private native void native_agps_set_id(int type, String setid); - - private static native boolean native_init_batching(); - - private static native void native_cleanup_batching(); - - private static native int native_get_batch_size(); - - private static native boolean native_start_batch(long periodNanos, boolean wakeOnFifoFull); - - private static native void native_flush_batch(); - - private static native boolean native_stop_batch(); + mGnssVisibilityControl.reportNfwNotification(proxyAppPackageName, protocolStack, + otherProtocolStackName, requestor, requestorId, responseType, inEmergencyMode, + isCachedLocation); + } } diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java index fa137aa43eb2e..ff92444640691 100644 --- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java +++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java @@ -19,99 +19,78 @@ package com.android.server.location.gnss; import android.Manifest; import android.annotation.Nullable; import android.content.Context; -import android.location.GnssAntennaInfo; +import android.hardware.location.GeofenceHardware; +import android.hardware.location.GeofenceHardwareImpl; +import android.location.FusedBatchOptions; +import android.location.GnssCapabilities; import android.location.GnssMeasurementCorrections; import android.location.GnssMeasurementRequest; -import android.location.GnssMeasurementsEvent; -import android.location.GnssNavigationMessage; import android.location.IGnssAntennaInfoListener; import android.location.IGnssMeasurementsListener; import android.location.IGnssNavigationMessageListener; +import android.location.IGnssNmeaListener; import android.location.IGnssStatusListener; import android.location.IGpsGeofenceHardware; -import android.location.INetInitiatedListener; import android.location.Location; -import android.location.LocationManagerInternal; import android.location.util.identity.CallerIdentity; +import android.os.BatteryStats; import android.os.RemoteException; +import android.os.ServiceManager; import android.util.IndentingPrintWriter; import android.util.Log; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Preconditions; -import com.android.server.LocalServices; -import com.android.server.location.injector.AppOpsHelper; +import com.android.internal.app.IBatteryStats; +import com.android.server.FgThread; +import com.android.server.location.gnss.hal.GnssNative; import com.android.server.location.injector.Injector; import java.io.FileDescriptor; -import java.util.List; /** Manages Gnss providers and related Gnss functions for LocationManagerService. */ -public class GnssManagerService implements GnssNative.Callbacks { +public class GnssManagerService { public static final String TAG = "GnssManager"; public static final boolean D = Log.isLoggable(TAG, Log.DEBUG); private static final String ATTRIBUTION_ID = "GnssService"; - public static boolean isGnssSupported() { - return GnssNative.isSupported(); - } - private final Context mContext; - private final AppOpsHelper mAppOpsHelper; - private final LocationManagerInternal mLocationManagerInternal; + private final GnssNative mGnssNative; private final GnssLocationProvider mGnssLocationProvider; private final GnssStatusProvider mGnssStatusProvider; + private final GnssNmeaProvider mGnssNmeaProvider; private final GnssMeasurementsProvider mGnssMeasurementsProvider; - private final GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider; private final GnssAntennaInfoProvider mGnssAntennaInfoProvider; private final GnssNavigationMessageProvider mGnssNavigationMessageProvider; - private final GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider; - private final GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider; - private final GnssCapabilitiesProvider mGnssCapabilitiesProvider; - private final INetInitiatedListener mNetInitiatedListener; - private final IGpsGeofenceHardware mGpsGeofenceProxy; + private final IGpsGeofenceHardware mGnssGeofenceProxy; - public GnssManagerService(Context context, Injector injector) { - this(context, injector, null); - } - - @VisibleForTesting - GnssManagerService(Context context, Injector injector, - GnssLocationProvider gnssLocationProvider) { - Preconditions.checkState(isGnssSupported()); - - GnssNative.initialize(); + private final GnssMetrics mGnssMetrics; + public GnssManagerService(Context context, Injector injector, GnssNative gnssNative) { mContext = context.createAttributionContext(ATTRIBUTION_ID); - mAppOpsHelper = injector.getAppOpsHelper(); - mLocationManagerInternal = LocalServices.getService(LocationManagerInternal.class); + mGnssNative = gnssNative; - if (gnssLocationProvider == null) { - gnssLocationProvider = new GnssLocationProvider(mContext, injector); - } + mGnssMetrics = new GnssMetrics(mContext, IBatteryStats.Stub.asInterface( + ServiceManager.getService(BatteryStats.SERVICE_NAME))); - mGnssLocationProvider = gnssLocationProvider; - mGnssStatusProvider = mGnssLocationProvider.getGnssStatusProvider(); - mGnssMeasurementsProvider = mGnssLocationProvider.getGnssMeasurementsProvider(); - mGnssAntennaInfoProvider = mGnssLocationProvider.getGnssAntennaInfoProvider(); - mGnssMeasurementCorrectionsProvider = - mGnssLocationProvider.getGnssMeasurementCorrectionsProvider(); - mGnssNavigationMessageProvider = mGnssLocationProvider.getGnssNavigationMessageProvider(); - mGnssSystemInfoProvider = mGnssLocationProvider.getGnssSystemInfoProvider(); - mGnssMetricsProvider = mGnssLocationProvider.getGnssMetricsProvider(); - mGnssCapabilitiesProvider = mGnssLocationProvider.getGnssCapabilitiesProvider(); - mNetInitiatedListener = mGnssLocationProvider.getNetInitiatedListener(); - mGpsGeofenceProxy = mGnssLocationProvider.getGpsGeofenceProxy(); + mGnssLocationProvider = new GnssLocationProvider(mContext, injector, mGnssNative, + mGnssMetrics); + mGnssStatusProvider = new GnssStatusProvider(injector, mGnssNative); + mGnssNmeaProvider = new GnssNmeaProvider(injector, mGnssNative); + mGnssMeasurementsProvider = new GnssMeasurementsProvider(injector, mGnssNative); + mGnssAntennaInfoProvider = new GnssAntennaInfoProvider(injector, mGnssNative); + mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(injector, mGnssNative); + mGnssGeofenceProxy = new GnssGeofenceProxy(mGnssNative); + + mGnssNative.setGeofenceCallbacks(new GnssGeofenceHalModule()); // allow gnss access to begin - we must assume that callbacks can start immediately - GnssNative.register(this); + mGnssNative.register(); } /** Called when system is ready. */ - public synchronized void onSystemReady() { + public void onSystemReady() { mGnssLocationProvider.onSystemReady(); } @@ -121,15 +100,15 @@ public class GnssManagerService implements GnssNative.Callbacks { } /** Retrieve the IGpsGeofenceHardware. */ - public IGpsGeofenceHardware getGpsGeofenceProxy() { - return mGpsGeofenceProxy; + public IGpsGeofenceHardware getGnssGeofenceProxy() { + return mGnssGeofenceProxy; } /** * Get year of GNSS hardware. */ public int getGnssYearOfHardware() { - return mGnssSystemInfoProvider.getGnssYearOfHardware(); + return mGnssNative.getHardwareYear(); } /** @@ -137,15 +116,15 @@ public class GnssManagerService implements GnssNative.Callbacks { */ @Nullable public String getGnssHardwareModelName() { - return mGnssSystemInfoProvider.getGnssHardwareModelName(); + return mGnssNative.getHardwareModelName(); } /** * Get GNSS hardware capabilities. The capabilities returned are a bitfield as described in * {@link android.location.GnssCapabilities}. */ - public long getGnssCapabilities() { - return mGnssCapabilitiesProvider.getGnssCapabilities(); + public GnssCapabilities getGnssCapabilities() { + return mGnssNative.getCapabilities(); } /** @@ -173,6 +152,24 @@ public class GnssManagerService implements GnssNative.Callbacks { mGnssStatusProvider.removeListener(listener); } + /** + * Registers listener for GNSS NMEA messages. + */ + public void registerGnssNmeaCallback(IGnssNmeaListener listener, String packageName, + @Nullable String attributionTag) { + mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null); + + CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag); + mGnssNmeaProvider.addListener(identity, listener); + } + + /** + * Unregisters listener for GNSS NMEA messages. + */ + public void unregisterGnssNmeaCallback(IGnssNmeaListener listener) { + mGnssNmeaProvider.removeListener(listener); + } + /** * Adds a GNSS measurements listener. */ @@ -192,7 +189,9 @@ public class GnssManagerService implements GnssNative.Callbacks { mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null); mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null); - mGnssMeasurementCorrectionsProvider.injectGnssMeasurementCorrections(corrections); + if (!mGnssNative.injectMeasurementCorrections(corrections)) { + Log.w(TAG, "failed to inject GNSS measurement corrections"); + } } /** @@ -248,9 +247,9 @@ public class GnssManagerService implements GnssNative.Callbacks { */ public void sendNiResponse(int notifId, int userResponse) { try { - mNetInitiatedListener.sendNiResponse(notifId, userResponse); + mGnssLocationProvider.getNetInitiatedListener().sendNiResponse(notifId, userResponse); } catch (RemoteException e) { - Log.e(TAG, "RemoteException in LocationManagerService.sendNiResponse"); + throw e.rethrowFromSystemServer(); } } @@ -259,12 +258,12 @@ public class GnssManagerService implements GnssNative.Callbacks { */ public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) { if (args.length > 0 && args[0].equals("--gnssmetrics")) { - if (mGnssMetricsProvider != null) { - ipw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString()); - } + ipw.append(mGnssMetrics.dumpGnssMetricsAsProtoString()); return; } + ipw.println("Capabilities: " + mGnssNative.getCapabilities()); + ipw.println("Antenna Info Provider:"); ipw.increaseIndent(); mGnssAntennaInfoProvider.dump(fd, ipw, args); @@ -284,169 +283,92 @@ public class GnssManagerService implements GnssNative.Callbacks { ipw.increaseIndent(); mGnssStatusProvider.dump(fd, ipw, args); ipw.decreaseIndent(); + + GnssPowerStats powerStats = mGnssNative.getPowerStats(); + if (powerStats != null) { + ipw.println("Last Power Stats:"); + ipw.increaseIndent(); + powerStats.dump(fd, ipw, args, mGnssNative.getCapabilities()); + ipw.decreaseIndent(); + } } - // all native callbacks - to be funneled to various locations as appropriate + private class GnssGeofenceHalModule implements GnssNative.GeofenceCallbacks { - @Override - public void reportLocation(boolean hasLatLong, Location location) { - mGnssLocationProvider.reportLocation(hasLatLong, location); - } + private GeofenceHardwareImpl mGeofenceHardwareImpl; - @Override - public void reportStatus(int status) { - mGnssLocationProvider.reportStatus(status); - } + private synchronized GeofenceHardwareImpl getGeofenceHardware() { + if (mGeofenceHardwareImpl == null) { + mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); + } + return mGeofenceHardwareImpl; + } - @Override - public void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0DbHzs, - float[] elevations, float[] azimuths, float[] carrierFrequencies, - float[] basebandCn0DbHzs) { - mGnssLocationProvider.reportSvStatus(svCount, svidWithFlags, cn0DbHzs, elevations, azimuths, - carrierFrequencies, basebandCn0DbHzs); - } + @Override + public void onReportGeofenceTransition(int geofenceId, Location location, + @GeofenceTransition int transition, long timestamp) { + FgThread.getHandler().post(() -> getGeofenceHardware().reportGeofenceTransition( + geofenceId, location, transition, timestamp, + GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, + FusedBatchOptions.SourceTechnologies.GNSS)); + } - @Override - public void reportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) { - mGnssLocationProvider.reportAGpsStatus(agpsType, agpsStatus, suplIpAddr); - } + @Override + public void onReportGeofenceStatus(@GeofenceAvailability int status, Location location) { + FgThread.getHandler().post(() -> { + int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE; + if (status == GEOFENCE_AVAILABILITY_AVAILABLE) { + monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE; + } + getGeofenceHardware().reportGeofenceMonitorStatus( + GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, + monitorStatus, + location, + FusedBatchOptions.SourceTechnologies.GNSS); + }); + } - @Override - public void reportNmea(long timestamp) { - mGnssLocationProvider.reportNmea(timestamp); - } + @Override + public void onReportGeofenceAddStatus(int geofenceId, @GeofenceStatus int status) { + FgThread.getHandler().post(() -> getGeofenceHardware().reportGeofenceAddStatus( + geofenceId, translateGeofenceStatus(status))); + } - @Override - public void reportMeasurementData(GnssMeasurementsEvent event) { - mGnssLocationProvider.reportMeasurementData(event); - } + @Override + public void onReportGeofenceRemoveStatus(int geofenceId, @GeofenceStatus int status) { + FgThread.getHandler().post(() -> getGeofenceHardware().reportGeofenceRemoveStatus( + geofenceId, translateGeofenceStatus(status))); + } - @Override - public void reportAntennaInfo(List antennaInfos) { - mGnssLocationProvider.reportAntennaInfo(antennaInfos); - } + @Override + public void onReportGeofencePauseStatus(int geofenceId, @GeofenceStatus int status) { + FgThread.getHandler().post(() -> getGeofenceHardware().reportGeofencePauseStatus( + geofenceId, translateGeofenceStatus(status))); + } - @Override - public void reportNavigationMessage(GnssNavigationMessage event) { - mGnssLocationProvider.reportNavigationMessage(event); - } + @Override + public void onReportGeofenceResumeStatus(int geofenceId, @GeofenceStatus int status) { + FgThread.getHandler().post(() -> getGeofenceHardware().reportGeofenceResumeStatus( + geofenceId, translateGeofenceStatus(status))); + } - @Override - public void reportGnssPowerStats(GnssPowerStats powerStats) { - mGnssLocationProvider.reportGnssPowerStats(powerStats); - } - - @Override - public void setTopHalCapabilities(int topHalCapabilities) { - mGnssLocationProvider.setTopHalCapabilities(topHalCapabilities); - } - - @Override - public void setSubHalMeasurementCorrectionsCapabilities(int subHalCapabilities) { - mGnssLocationProvider.setSubHalMeasurementCorrectionsCapabilities(subHalCapabilities); - } - - @Override - public void setSubHalPowerIndicationCapabilities(int subHalCapabilities) { - mGnssLocationProvider.setSubHalPowerIndicationCapabilities(subHalCapabilities); - } - - @Override - public void setGnssYearOfHardware(int yearOfHardware) { - mGnssLocationProvider.setGnssYearOfHardware(yearOfHardware); - } - - @Override - public void setGnssHardwareModelName(String modelName) { - mGnssLocationProvider.setGnssHardwareModelName(modelName); - } - - @Override - public void reportGnssServiceRestarted() { - mGnssLocationProvider.reportGnssServiceRestarted(); - } - - @Override - public void reportLocationBatch(Location[] locationArray) { - mGnssLocationProvider.reportLocationBatch(locationArray); - } - - @Override - public void psdsDownloadRequest(int psdsType) { - mGnssLocationProvider.downloadPsdsData(psdsType); - } - - @Override - public void reportGeofenceTransition(int geofenceId, Location location, int transition, - long transitionTimestamp) { - mGnssLocationProvider.reportGeofenceTransition(geofenceId, location, transition, - transitionTimestamp); - } - - @Override - public void reportGeofenceStatus(int status, Location location) { - mGnssLocationProvider.reportGeofenceStatus(status, location); - } - - @Override - public void reportGeofenceAddStatus(int geofenceId, int status) { - mGnssLocationProvider.reportGeofenceAddStatus(geofenceId, status); - } - - @Override - public void reportGeofenceRemoveStatus(int geofenceId, int status) { - mGnssLocationProvider.reportGeofenceRemoveStatus(geofenceId, status); - } - - @Override - public void reportGeofencePauseStatus(int geofenceId, int status) { - mGnssLocationProvider.reportGeofencePauseStatus(geofenceId, status); - } - - @Override - public void reportGeofenceResumeStatus(int geofenceId, int status) { - mGnssLocationProvider.reportGeofenceResumeStatus(geofenceId, status); - } - - @Override - public void reportNiNotification(int notificationId, int niType, int notifyFlags, - int timeout, int defaultResponse, String requestorId, String text, - int requestorIdEncoding, int textEncoding) { - mGnssLocationProvider.reportNiNotification(notificationId, niType, notifyFlags, timeout, - defaultResponse, requestorId, text, requestorIdEncoding, textEncoding); - } - - @Override - public void requestSetID(int flags) { - mGnssLocationProvider.requestSetID(flags); - } - - @Override - public void requestLocation(boolean independentFromGnss, boolean isUserEmergency) { - mGnssLocationProvider.requestLocation(independentFromGnss, isUserEmergency); - } - - @Override - public void requestUtcTime() { - mGnssLocationProvider.requestUtcTime(); - } - - @Override - public void requestRefLocation() { - mGnssLocationProvider.requestRefLocation(); - } - - @Override - public void reportNfwNotification(String proxyAppPackageName, byte protocolStack, - String otherProtocolStackName, byte requestor, String requestorId, - byte responseType, boolean inEmergencyMode, boolean isCachedLocation) { - mGnssLocationProvider.reportNfwNotification(proxyAppPackageName, protocolStack, - otherProtocolStackName, requestor, requestorId, responseType, inEmergencyMode, - isCachedLocation); - } - - @Override - public boolean isInEmergencySession() { - return mGnssLocationProvider.isInEmergencySession(); + private int translateGeofenceStatus(@GeofenceStatus int status) { + switch (status) { + case GEOFENCE_STATUS_OPERATION_SUCCESS: + return GeofenceHardware.GEOFENCE_SUCCESS; + case GEOFENCE_STATUS_ERROR_GENERIC: + return GeofenceHardware.GEOFENCE_FAILURE; + case GEOFENCE_STATUS_ERROR_ID_EXISTS: + return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS; + case GEOFENCE_STATUS_ERROR_INVALID_TRANSITION: + return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION; + case GEOFENCE_STATUS_ERROR_TOO_MANY_GEOFENCES: + return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES; + case GEOFENCE_STATUS_ERROR_ID_UNKNOWN: + return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN; + default: + return -1; + } + } } } diff --git a/services/core/java/com/android/server/location/gnss/GnssMeasurementCorrectionsProvider.java b/services/core/java/com/android/server/location/gnss/GnssMeasurementCorrectionsProvider.java deleted file mode 100644 index 4401f29b4e57a..0000000000000 --- a/services/core/java/com/android/server/location/gnss/GnssMeasurementCorrectionsProvider.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.location.gnss; - -import android.location.GnssMeasurementCorrections; -import android.os.Handler; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; - -/** - * Manages GNSS measurement corrections. - * - *

Implements the framework side of the GNSS HAL interfaces {@code IMeasurementCorrections.hal} - * and {@code IMeasurementCorrectionsCallback.hal). - * - * @hide - */ -public class GnssMeasurementCorrectionsProvider { - private static final String TAG = "GnssMeasurementCorrectionsProvider"; - - // These must match with the Capabilities enum in IMeasurementCorrectionsCallback.hal. - static final int CAPABILITY_LOS_SATS = 0x0000001; - static final int CAPABILITY_EXCESS_PATH_LENGTH = 0x0000002; - static final int CAPABILITY_REFLECTING_PLANE = 0x0000004; - - private static final int INVALID_CAPABILITIES = 1 << 31; - - private final Handler mHandler; - private final GnssMeasurementCorrectionsProviderNative mNative; - private volatile int mCapabilities = INVALID_CAPABILITIES; - - GnssMeasurementCorrectionsProvider(Handler handler) { - this(handler, new GnssMeasurementCorrectionsProviderNative()); - } - - @VisibleForTesting - GnssMeasurementCorrectionsProvider(Handler handler, - GnssMeasurementCorrectionsProviderNative aNative) { - mHandler = handler; - mNative = aNative; - } - - /** - * Returns {@code true} if the GNSS HAL implementation supports measurement corrections. - */ - public boolean isAvailableInPlatform() { - return mNative.isMeasurementCorrectionsSupported(); - } - - /** - * Injects GNSS measurement corrections into the GNSS chipset. - * - * @param measurementCorrections a {@link GnssMeasurementCorrections} object with the GNSS - * measurement corrections to be injected into the GNSS chipset. - */ - public void injectGnssMeasurementCorrections( - GnssMeasurementCorrections measurementCorrections) { - if (!isCapabilitiesReceived()) { - Log.w(TAG, "Failed to inject GNSS measurement corrections. Capabilities " - + "not received yet."); - return; - } - mHandler.post(() -> { - if (!mNative.injectGnssMeasurementCorrections(measurementCorrections)) { - Log.e(TAG, "Failure in injecting GNSS corrections."); - } - }); - } - - /** Handle measurement corrections capabilities update from the GNSS HAL implementation. */ - boolean onCapabilitiesUpdated(int capabilities) { - if (hasCapability(capabilities, CAPABILITY_LOS_SATS) || hasCapability(capabilities, - CAPABILITY_EXCESS_PATH_LENGTH)) { - mCapabilities = capabilities; - return true; - } else { - Log.e(TAG, "Failed to set capabilities. Received capabilities 0x" - + Integer.toHexString(capabilities) + " does not contain the mandatory " - + "LOS_SATS or the EXCESS_PATH_LENGTH capability."); - return false; - } - } - - /** - * Returns the measurement corrections specific capabilities of the GNSS HAL implementation. - */ - int getCapabilities() { - return mCapabilities; - } - - /** - * Returns the string representation of the GNSS measurement capabilities. - */ - String toStringCapabilities() { - final int capabilities = getCapabilities(); - StringBuilder s = new StringBuilder(); - s.append("mCapabilities=0x").append(Integer.toHexString(capabilities)); - s.append(" ( "); - if (hasCapability(capabilities, CAPABILITY_LOS_SATS)) { - s.append("LOS_SATS "); - } - if (hasCapability(capabilities, CAPABILITY_EXCESS_PATH_LENGTH)) { - s.append("EXCESS_PATH_LENGTH "); - } - if (hasCapability(capabilities, CAPABILITY_REFLECTING_PLANE)) { - s.append("REFLECTING_PLANE "); - } - s.append(")"); - return s.toString(); - } - - private static boolean hasCapability(int halCapabilities, int capability) { - return (halCapabilities & capability) != 0; - } - - private boolean isCapabilitiesReceived() { - return mCapabilities != INVALID_CAPABILITIES; - } - - @VisibleForTesting - static class GnssMeasurementCorrectionsProviderNative { - public boolean isMeasurementCorrectionsSupported() { - return native_is_measurement_corrections_supported(); - } - - public boolean injectGnssMeasurementCorrections( - GnssMeasurementCorrections measurementCorrections) { - return native_inject_gnss_measurement_corrections(measurementCorrections); - } - } - - static native boolean native_is_measurement_corrections_supported(); - - static native boolean native_inject_gnss_measurement_corrections( - GnssMeasurementCorrections measurementCorrections); -} diff --git a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java index fa8e2a6f34b3e..b7cc9f51bfec6 100644 --- a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java @@ -21,6 +21,7 @@ import static com.android.server.location.gnss.GnssManagerService.TAG; import android.annotation.Nullable; import android.app.AppOpsManager; +import android.location.GnssCapabilities; import android.location.GnssMeasurementRequest; import android.location.GnssMeasurementsEvent; import android.location.IGnssMeasurementsListener; @@ -29,8 +30,7 @@ import android.os.IBinder; import android.stats.location.LocationStatsEnums; import android.util.Log; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Preconditions; +import com.android.server.location.gnss.hal.GnssNative; import com.android.server.location.injector.AppOpsHelper; import com.android.server.location.injector.Injector; import com.android.server.location.injector.LocationAttributionHelper; @@ -38,7 +38,6 @@ import com.android.server.location.injector.LocationUsageLogger; import com.android.server.location.injector.SettingsHelper; import java.util.Collection; -import java.util.Objects; /** * An base implementation for GNSS measurements provider. It abstracts out the responsibility of @@ -47,8 +46,10 @@ import java.util.Objects; * @hide */ public final class GnssMeasurementsProvider extends - GnssListenerMultiplexer - implements SettingsHelper.GlobalSettingChangedListener { + GnssListenerMultiplexer implements + SettingsHelper.GlobalSettingChangedListener, GnssNative.BaseCallbacks, + GnssNative.MeasurementCallbacks { private class GnssMeasurementListenerRegistration extends GnssListenerRegistration { @@ -79,24 +80,22 @@ public final class GnssMeasurementsProvider extends private final AppOpsHelper mAppOpsHelper; private final LocationAttributionHelper mLocationAttributionHelper; private final LocationUsageLogger mLogger; - private final GnssMeasurementProviderNative mNative; + private final GnssNative mGnssNative; - public GnssMeasurementsProvider(Injector injector) { - this(injector, new GnssMeasurementProviderNative()); - } - - @VisibleForTesting - public GnssMeasurementsProvider(Injector injector, GnssMeasurementProviderNative aNative) { + public GnssMeasurementsProvider(Injector injector, GnssNative gnssNative) { super(injector); mAppOpsHelper = injector.getAppOpsHelper(); mLocationAttributionHelper = injector.getLocationAttributionHelper(); mLogger = injector.getLocationUsageLogger(); - mNative = aNative; + mGnssNative = gnssNative; + + mGnssNative.addBaseCallbacks(this); + mGnssNative.addMeasurementCallbacks(this); } @Override protected boolean isServiceSupported() { - return mNative.isMeasurementSupported(); + return mGnssNative.isMeasurementSupported(); } @Override @@ -112,17 +111,14 @@ public final class GnssMeasurementsProvider extends } @Override - protected boolean registerWithService(Boolean fullTrackingRequest, + protected boolean registerWithService(GnssMeasurementRequest request, Collection registrations) { - Preconditions.checkState(mNative.isMeasurementSupported()); - - if (mNative.startMeasurementCollection(fullTrackingRequest)) { + if (mGnssNative.startMeasurementCollection(request.isFullTracking())) { if (D) { - Log.d(TAG, "starting gnss measurements (" + fullTrackingRequest + ")"); + Log.d(TAG, "starting gnss measurements (" + request + ")"); } return true; } else { - Log.e(TAG, "error starting gnss measurements"); return false; } @@ -130,14 +126,12 @@ public final class GnssMeasurementsProvider extends @Override protected void unregisterWithService() { - if (mNative.isMeasurementSupported()) { - if (mNative.stopMeasurementCollection()) { - if (D) { - Log.d(TAG, "stopping gnss measurements"); - } - } else { - Log.e(TAG, "error stopping gnss measurements"); + if (mGnssNative.stopMeasurementCollection()) { + if (D) { + Log.d(TAG, "stopping gnss measurements"); } + } else { + Log.e(TAG, "error stopping gnss measurements"); } } @@ -158,18 +152,21 @@ public final class GnssMeasurementsProvider extends } @Override - protected Boolean mergeRegistrations(Collection registrations) { + protected GnssMeasurementRequest mergeRegistrations( + Collection registrations) { + boolean fullTracking = false; if (mSettingsHelper.isGnssMeasurementsFullTrackingEnabled()) { - return true; - } - - for (GnssListenerRegistration registration : registrations) { - if (Objects.requireNonNull(registration.getRequest()).isFullTracking()) { - return true; + fullTracking = true; + } else { + for (GnssListenerRegistration registration : registrations) { + if (registration.getRequest().isFullTracking()) { + fullTracking = true; + break; + } } } - return false; + return new GnssMeasurementRequest.Builder().setFullTracking(fullTracking).build(); } @Override @@ -198,10 +195,17 @@ public final class GnssMeasurementsProvider extends null, registration.isForeground()); } - /** - * Called by GnssLocationProvider. - */ - public void onMeasurementsAvailable(GnssMeasurementsEvent event) { + @Override + public void onHalRestarted() { + resetService(); + } + + @Override + public void onCapabilitiesChanged(GnssCapabilities oldCapabilities, + GnssCapabilities newCapabilities) {} + + @Override + public void onReportMeasurements(GnssMeasurementsEvent event) { deliverToListeners(registration -> { if (mAppOpsHelper.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION, registration.getIdentity())) { @@ -211,25 +215,4 @@ public final class GnssMeasurementsProvider extends } }); } - - @VisibleForTesting - static class GnssMeasurementProviderNative { - boolean isMeasurementSupported() { - return native_is_measurement_supported(); - } - - boolean startMeasurementCollection(boolean enableFullTracking) { - return native_start_measurement_collection(enableFullTracking); - } - - boolean stopMeasurementCollection() { - return native_stop_measurement_collection(); - } - } - - static native boolean native_is_measurement_supported(); - - static native boolean native_start_measurement_collection(boolean enableFullTracking); - - static native boolean native_stop_measurement_collection(); } diff --git a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java b/services/core/java/com/android/server/location/gnss/GnssMetrics.java similarity index 96% rename from location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java rename to services/core/java/com/android/server/location/gnss/GnssMetrics.java index dd8a8c3bd1d5b..c7d8144342ab7 100644 --- a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java +++ b/services/core/java/com/android/server/location/gnss/GnssMetrics.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,15 +14,11 @@ * limitations under the License. */ -package com.android.internal.location.gnssmetrics; - -import static android.location.GnssSignalQuality.GNSS_SIGNAL_QUALITY_GOOD; -import static android.location.GnssSignalQuality.GNSS_SIGNAL_QUALITY_POOR; -import static android.location.GnssSignalQuality.GNSS_SIGNAL_QUALITY_UNKNOWN; -import static android.location.GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS; +package com.android.server.location.gnss; import android.app.StatsManager; import android.content.Context; +import android.location.GnssSignalQuality; import android.location.GnssStatus; import android.os.RemoteException; import android.os.SystemClock; @@ -67,11 +63,11 @@ public class GnssMetrics { // A boolean array indicating whether the constellation types have been used in fix. private boolean[] mConstellationTypes; - private Statistics mLocationFailureStatistics; - private Statistics mTimeToFirstFixSecStatistics; - private Statistics mPositionAccuracyMeterStatistics; - private Statistics mTopFourAverageCn0Statistics; - private Statistics mTopFourAverageCn0StatisticsL5; + private final Statistics mLocationFailureStatistics; + private final Statistics mTimeToFirstFixSecStatistics; + private final Statistics mPositionAccuracyMeterStatistics; + private final Statistics mTopFourAverageCn0Statistics; + private final Statistics mTopFourAverageCn0StatisticsL5; // Total number of sv status messages processed private int mNumSvStatus; // Total number of L5 sv status messages processed @@ -91,7 +87,7 @@ public class GnssMetrics { long mSvStatusReportsUsedInFix; long mL5SvStatusReportsUsedInFix; - private StatsManager mStatsManager; + private final StatsManager mStatsManager; public GnssMetrics(Context context, IBatteryStats stats) { mGnssPowerMetrics = new GnssPowerMetrics(stats); @@ -390,7 +386,7 @@ public class GnssMetrics { stats.getLoggingDurationMs() / ((double) DateUtils.MINUTE_IN_MILLIS)).append( "\n"); long[] t = stats.getTimeInGpsSignalQualityLevel(); - if (t != null && t.length == NUM_GNSS_SIGNAL_QUALITY_LEVELS) { + if (t != null && t.length == GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS) { s.append(" Amount of time (while on battery) Top 4 Avg CN0 > " + GnssPowerMetrics.POOR_TOP_FOUR_AVG_CN0_THRESHOLD_DB_HZ + " dB-Hz (min): ").append( @@ -505,7 +501,7 @@ public class GnssMetrics { // so that // the first CNO report will trigger an update to BatteryStats mLastAverageCn0 = -100.0; - mLastSignalLevel = GNSS_SIGNAL_QUALITY_UNKNOWN; + mLastSignalLevel = GnssSignalQuality.GNSS_SIGNAL_QUALITY_UNKNOWN; } /** @@ -577,9 +573,9 @@ public class GnssMetrics { */ private int getSignalLevel(double cn0) { if (cn0 > POOR_TOP_FOUR_AVG_CN0_THRESHOLD_DB_HZ) { - return GNSS_SIGNAL_QUALITY_GOOD; + return GnssSignalQuality.GNSS_SIGNAL_QUALITY_GOOD; } - return GNSS_SIGNAL_QUALITY_POOR; + return GnssSignalQuality.GNSS_SIGNAL_QUALITY_POOR; } } diff --git a/services/core/java/com/android/server/location/gnss/GnssNative.java b/services/core/java/com/android/server/location/gnss/GnssNative.java deleted file mode 100644 index 4494c191a16bf..0000000000000 --- a/services/core/java/com/android/server/location/gnss/GnssNative.java +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.location.gnss; - -import android.location.GnssAntennaInfo; -import android.location.GnssMeasurementsEvent; -import android.location.GnssNavigationMessage; -import android.location.Location; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Preconditions; -import com.android.server.FgThread; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.List; - -/** - * Entry point for all GNSS native callbacks, and responsible for initializing the GNSS HAL. - */ -class GnssNative { - - interface Callbacks { - void reportLocation(boolean hasLatLong, Location location); - void reportStatus(int status); - void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0DbHzs, - float[] elevations, float[] azimuths, float[] carrierFrequencies, - float[] basebandCn0DbHzs); - void reportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr); - void reportNmea(long timestamp); - void reportMeasurementData(GnssMeasurementsEvent event); - void reportAntennaInfo(List antennaInfos); - void reportNavigationMessage(GnssNavigationMessage event); - void reportGnssPowerStats(GnssPowerStats powerStats); - void setTopHalCapabilities(int topHalCapabilities); - void setSubHalMeasurementCorrectionsCapabilities(int subHalCapabilities); - void setSubHalPowerIndicationCapabilities(int subHalCapabilities); - void setGnssYearOfHardware(int yearOfHardware); - void setGnssHardwareModelName(String modelName); - void reportGnssServiceRestarted(); - void reportLocationBatch(Location[] locationArray); - void psdsDownloadRequest(int psdsType); - void reportGeofenceTransition(int geofenceId, Location location, int transition, - long transitionTimestamp); - void reportGeofenceStatus(int status, Location location); - void reportGeofenceAddStatus(int geofenceId, int status); - void reportGeofenceRemoveStatus(int geofenceId, int status); - void reportGeofencePauseStatus(int geofenceId, int status); - void reportGeofenceResumeStatus(int geofenceId, int status); - void reportNiNotification( - int notificationId, - int niType, - int notifyFlags, - int timeout, - int defaultResponse, - String requestorId, - String text, - int requestorIdEncoding, - int textEncoding - ); - void requestSetID(int flags); - void requestLocation(boolean independentFromGnss, boolean isUserEmergency); - void requestUtcTime(); - void requestRefLocation(); - void reportNfwNotification(String proxyAppPackageName, byte protocolStack, - String otherProtocolStackName, byte requestor, String requestorId, - byte responseType, boolean inEmergencyMode, boolean isCachedLocation); - boolean isInEmergencySession(); - } - - /** - * Indicates that this method is a native entry point. Useful purely for IDEs which can - * understand entry points, and thus eliminate incorrect warnings about methods not used. - */ - @Target(ElementType.METHOD) - @Retention(RetentionPolicy.SOURCE) - private @interface NativeEntryPoint {} - - @GuardedBy("GnssNative.class") - private static boolean sInitialized; - - @GuardedBy("GnssNative.class") - private static GnssNativeInitNative sInitNative = new GnssNativeInitNative(); - - @GuardedBy("GnssNative.class") - private static GnssNative sInstance; - - @VisibleForTesting - public static synchronized void setInitNativeForTest(GnssNativeInitNative initNative) { - sInitNative = initNative; - } - - public static synchronized boolean isSupported() { - initialize(); - return sInitNative.isSupported(); - } - - static synchronized void initialize() { - if (!sInitialized) { - sInitNative.classInitOnce(); - sInitialized = true; - } - } - - @VisibleForTesting - public static synchronized void resetCallbacksForTest() { - sInstance = null; - } - - static synchronized void register(Callbacks callbacks) { - Preconditions.checkState(sInstance == null); - initialize(); - sInstance = new GnssNative(callbacks); - } - - private final Callbacks mCallbacks; - - private GnssNative(Callbacks callbacks) { - mCallbacks = callbacks; - sInitNative.initOnce(this, false); - } - - @NativeEntryPoint - private void reportLocation(boolean hasLatLong, Location location) { - mCallbacks.reportLocation(hasLatLong, location); - } - - @NativeEntryPoint - private void reportStatus(int status) { - mCallbacks.reportStatus(status); - } - - @NativeEntryPoint - private void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0DbHzs, - float[] elevations, float[] azimuths, float[] carrierFrequencies, - float[] basebandCn0DbHzs) { - mCallbacks.reportSvStatus(svCount, svidWithFlags, cn0DbHzs, elevations, azimuths, - carrierFrequencies, basebandCn0DbHzs); - } - - @NativeEntryPoint - private void reportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) { - mCallbacks.reportAGpsStatus(agpsType, agpsStatus, suplIpAddr); - } - - @NativeEntryPoint - private void reportNmea(long timestamp) { - mCallbacks.reportNmea(timestamp); - } - - @NativeEntryPoint - private void reportMeasurementData(GnssMeasurementsEvent event) { - mCallbacks.reportMeasurementData(event); - } - - @NativeEntryPoint - private void reportAntennaInfo(List antennaInfos) { - mCallbacks.reportAntennaInfo(antennaInfos); - } - - @NativeEntryPoint - private void reportNavigationMessage(GnssNavigationMessage event) { - mCallbacks.reportNavigationMessage(event); - } - - @NativeEntryPoint - private void reportGnssPowerStats(GnssPowerStats powerStats) { - mCallbacks.reportGnssPowerStats(powerStats); - } - - @NativeEntryPoint - private void setTopHalCapabilities(int topHalCapabilities) { - mCallbacks.setTopHalCapabilities(topHalCapabilities); - } - - @NativeEntryPoint - private void setSubHalMeasurementCorrectionsCapabilities(int subHalCapabilities) { - mCallbacks.setSubHalMeasurementCorrectionsCapabilities(subHalCapabilities); - } - - @NativeEntryPoint - private void setSubHalPowerIndicationCapabilities(int subHalCapabilities) { - mCallbacks.setSubHalPowerIndicationCapabilities(subHalCapabilities); - } - - @NativeEntryPoint - private void setGnssYearOfHardware(int yearOfHardware) { - mCallbacks.setGnssYearOfHardware(yearOfHardware); - } - - @NativeEntryPoint - private void setGnssHardwareModelName(String modelName) { - mCallbacks.setGnssHardwareModelName(modelName); - } - - @NativeEntryPoint - private void reportGnssServiceDied() { - FgThread.getExecutor().execute(() -> { - sInitNative.initOnce(GnssNative.this, true); - mCallbacks.reportGnssServiceRestarted(); - }); - } - - @NativeEntryPoint - private void reportLocationBatch(Location[] locationArray) { - mCallbacks.reportLocationBatch(locationArray); - } - - @NativeEntryPoint - private void psdsDownloadRequest(int psdsType) { - mCallbacks.psdsDownloadRequest(psdsType); - } - - @NativeEntryPoint - private void reportGeofenceTransition(int geofenceId, Location location, int transition, - long transitionTimestamp) { - mCallbacks.reportGeofenceTransition(geofenceId, location, transition, transitionTimestamp); - } - - @NativeEntryPoint - private void reportGeofenceStatus(int status, Location location) { - mCallbacks.reportGeofenceStatus(status, location); - } - - @NativeEntryPoint - private void reportGeofenceAddStatus(int geofenceId, int status) { - mCallbacks.reportGeofenceAddStatus(geofenceId, status); - } - - @NativeEntryPoint - private void reportGeofenceRemoveStatus(int geofenceId, int status) { - mCallbacks.reportGeofenceRemoveStatus(geofenceId, status); - } - - @NativeEntryPoint - private void reportGeofencePauseStatus(int geofenceId, int status) { - mCallbacks.reportGeofencePauseStatus(geofenceId, status); - } - - @NativeEntryPoint - private void reportGeofenceResumeStatus(int geofenceId, int status) { - mCallbacks.reportGeofenceResumeStatus(geofenceId, status); - } - - @NativeEntryPoint - private void reportNiNotification(int notificationId, int niType, int notifyFlags, - int timeout, int defaultResponse, String requestorId, String text, - int requestorIdEncoding, int textEncoding) { - mCallbacks.reportNiNotification(notificationId, niType, notifyFlags, timeout, - defaultResponse, requestorId, text, requestorIdEncoding, textEncoding); - } - - @NativeEntryPoint - private void requestSetID(int flags) { - mCallbacks.requestSetID(flags); - } - - @NativeEntryPoint - private void requestLocation(boolean independentFromGnss, boolean isUserEmergency) { - mCallbacks.requestLocation(independentFromGnss, isUserEmergency); - } - - @NativeEntryPoint - private void requestUtcTime() { - mCallbacks.requestUtcTime(); - } - - @NativeEntryPoint - private void requestRefLocation() { - mCallbacks.requestRefLocation(); - } - - @NativeEntryPoint - private void reportNfwNotification(String proxyAppPackageName, byte protocolStack, - String otherProtocolStackName, byte requestor, String requestorId, - byte responseType, boolean inEmergencyMode, boolean isCachedLocation) { - mCallbacks.reportNfwNotification(proxyAppPackageName, protocolStack, otherProtocolStackName, - requestor, requestorId, responseType, inEmergencyMode, isCachedLocation); - } - - @NativeEntryPoint - private boolean isInEmergencySession() { - return mCallbacks.isInEmergencySession(); - } - - @VisibleForTesting - public static class GnssNativeInitNative { - - public void classInitOnce() { - native_class_init_once(); - } - - public boolean isSupported() { - return native_is_supported(); - } - - public void initOnce(GnssNative gnssNative, boolean reinitializeGnssServiceHandle) { - gnssNative.native_init_once(reinitializeGnssServiceHandle); - } - } - - static native void native_class_init_once(); - - static native boolean native_is_supported(); - - native void native_init_once(boolean reinitializeGnssServiceHandle); -} diff --git a/services/core/java/com/android/server/location/gnss/GnssNavigationMessageProvider.java b/services/core/java/com/android/server/location/gnss/GnssNavigationMessageProvider.java index 92491f7ecd5a4..9b1cde0d967c7 100644 --- a/services/core/java/com/android/server/location/gnss/GnssNavigationMessageProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssNavigationMessageProvider.java @@ -20,13 +20,13 @@ import static com.android.server.location.gnss.GnssManagerService.D; import static com.android.server.location.gnss.GnssManagerService.TAG; import android.app.AppOpsManager; +import android.location.GnssCapabilities; import android.location.GnssNavigationMessage; import android.location.IGnssNavigationMessageListener; import android.location.util.identity.CallerIdentity; import android.util.Log; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Preconditions; +import com.android.server.location.gnss.hal.GnssNative; import com.android.server.location.injector.AppOpsHelper; import com.android.server.location.injector.Injector; @@ -40,21 +40,24 @@ import java.util.Collection; * @hide */ public class GnssNavigationMessageProvider extends - GnssListenerMultiplexer { + GnssListenerMultiplexer implements + GnssNative.BaseCallbacks, GnssNative.NavigationMessageCallbacks { private final AppOpsHelper mAppOpsHelper; - private final GnssNavigationMessageProviderNative mNative; + private final GnssNative mGnssNative; - public GnssNavigationMessageProvider(Injector injector) { - this(injector, new GnssNavigationMessageProviderNative()); - } - - @VisibleForTesting - public GnssNavigationMessageProvider(Injector injector, - GnssNavigationMessageProviderNative aNative) { + public GnssNavigationMessageProvider(Injector injector, GnssNative gnssNative) { super(injector); mAppOpsHelper = injector.getAppOpsHelper(); - mNative = aNative; + mGnssNative = gnssNative; + + mGnssNative.addBaseCallbacks(this); + mGnssNative.addNavigationMessageCallbacks(this); + } + + @Override + protected boolean isServiceSupported() { + return mGnssNative.isNavigationMessageCollectionSupported(); } @Override @@ -65,9 +68,7 @@ public class GnssNavigationMessageProvider extends @Override protected boolean registerWithService(Void ignored, Collection registrations) { - Preconditions.checkState(mNative.isNavigationMessageSupported()); - - if (mNative.startNavigationMessageCollection()) { + if (mGnssNative.startNavigationMessageCollection()) { if (D) { Log.d(TAG, "starting gnss navigation messages"); } @@ -80,21 +81,26 @@ public class GnssNavigationMessageProvider extends @Override protected void unregisterWithService() { - if (mNative.isNavigationMessageSupported()) { - if (mNative.stopNavigationMessageCollection()) { - if (D) { - Log.d(TAG, "stopping gnss navigation messages"); - } - } else { - Log.e(TAG, "error stopping gnss navigation messages"); + if (mGnssNative.stopNavigationMessageCollection()) { + if (D) { + Log.d(TAG, "stopping gnss navigation messages"); } + } else { + Log.e(TAG, "error stopping gnss navigation messages"); } } - /** - * Called by GnssLocationProvider. - */ - public void onNavigationMessageAvailable(GnssNavigationMessage event) { + @Override + public void onHalRestarted() { + resetService(); + } + + @Override + public void onCapabilitiesChanged(GnssCapabilities oldCapabilities, + GnssCapabilities newCapabilities) {} + + @Override + public void onReportNavigationMessage(GnssNavigationMessage event) { deliverToListeners(registration -> { if (mAppOpsHelper.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION, registration.getIdentity())) { @@ -104,30 +110,4 @@ public class GnssNavigationMessageProvider extends } }); } - - @Override - protected boolean isServiceSupported() { - return mNative.isNavigationMessageSupported(); - } - - @VisibleForTesting - static class GnssNavigationMessageProviderNative { - boolean isNavigationMessageSupported() { - return native_is_navigation_message_supported(); - } - - boolean startNavigationMessageCollection() { - return native_start_navigation_message_collection(); - } - - boolean stopNavigationMessageCollection() { - return native_stop_navigation_message_collection(); - } - } - - static native boolean native_is_navigation_message_supported(); - - static native boolean native_start_navigation_message_collection(); - - static native boolean native_stop_navigation_message_collection(); } diff --git a/services/core/java/com/android/server/location/gnss/GnssNmeaProvider.java b/services/core/java/com/android/server/location/gnss/GnssNmeaProvider.java new file mode 100644 index 0000000000000..bad1b79e3568e --- /dev/null +++ b/services/core/java/com/android/server/location/gnss/GnssNmeaProvider.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.location.gnss; + +import static com.android.server.location.gnss.GnssManagerService.D; +import static com.android.server.location.gnss.GnssManagerService.TAG; + +import android.annotation.Nullable; +import android.app.AppOpsManager; +import android.location.GnssCapabilities; +import android.location.IGnssNmeaListener; +import android.location.util.identity.CallerIdentity; +import android.util.Log; + +import com.android.internal.listeners.ListenerExecutor; +import com.android.server.location.gnss.hal.GnssNative; +import com.android.server.location.injector.AppOpsHelper; +import com.android.server.location.injector.Injector; + +import java.util.Collection; +import java.util.function.Function; + +/** + * Implementation of a handler for {@link IGnssNmeaListener}. + */ +class GnssNmeaProvider extends GnssListenerMultiplexer implements + GnssNative.BaseCallbacks, GnssNative.NmeaCallbacks { + + private final AppOpsHelper mAppOpsHelper; + private final GnssNative mGnssNative; + + // preallocated to avoid memory allocation in onReportNmea() + private final byte[] mNmeaBuffer = new byte[120]; + + GnssNmeaProvider(Injector injector, GnssNative gnssNative) { + super(injector); + + mAppOpsHelper = injector.getAppOpsHelper(); + mGnssNative = gnssNative; + + mGnssNative.addBaseCallbacks(this); + mGnssNative.addNmeaCallbacks(this); + } + + @Override + public void addListener(CallerIdentity identity, IGnssNmeaListener listener) { + super.addListener(identity, listener); + } + + @Override + protected boolean registerWithService(Void ignored, + Collection registrations) { + if (D) { + Log.d(TAG, "starting gnss nmea messages"); + } + return true; + } + + @Override + protected void unregisterWithService() { + if (D) { + Log.d(TAG, "stopping gnss nmea messages"); + } + } + + @Override + public void onHalRestarted() { + resetService(); + } + + @Override + public void onCapabilitiesChanged(GnssCapabilities oldCapabilities, + GnssCapabilities newCapabilities) {} + + @Override + public void onReportNmea(long timestamp) { + deliverToListeners( + new Function>() { + + // only read in the nmea string if we need to + private @Nullable String mNmea; + + @Override + public ListenerExecutor.ListenerOperation apply( + GnssListenerRegistration registration) { + if (mAppOpsHelper.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION, + registration.getIdentity())) { + if (mNmea == null) { + int length = mGnssNative.readNmea(mNmeaBuffer, + mNmeaBuffer.length); + mNmea = new String(mNmeaBuffer, 0, length); + } + return listener -> listener.onNmeaReceived(timestamp, mNmea); + } else { + return null; + } + } + }); + } +} diff --git a/services/core/java/com/android/server/location/gnss/GnssPowerIndicationProvider.java b/services/core/java/com/android/server/location/gnss/GnssPowerIndicationProvider.java deleted file mode 100644 index 5941a33298dd3..0000000000000 --- a/services/core/java/com/android/server/location/gnss/GnssPowerIndicationProvider.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.location.gnss; - -import static android.hardware.gnss.IGnssPowerIndicationCallback.CAPABILITY_MULTIBAND_ACQUISITION; -import static android.hardware.gnss.IGnssPowerIndicationCallback.CAPABILITY_MULTIBAND_TRACKING; -import static android.hardware.gnss.IGnssPowerIndicationCallback.CAPABILITY_OTHER_MODES; -import static android.hardware.gnss.IGnssPowerIndicationCallback.CAPABILITY_SINGLEBAND_ACQUISITION; -import static android.hardware.gnss.IGnssPowerIndicationCallback.CAPABILITY_SINGLEBAND_TRACKING; -import static android.hardware.gnss.IGnssPowerIndicationCallback.CAPABILITY_TOTAL; - -import android.util.Log; - -import java.io.FileDescriptor; -import java.io.PrintWriter; - -/** - * Manages GNSS Power Indication operations. - */ -class GnssPowerIndicationProvider { - private static final String TAG = "GnssPowerIndPdr"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - private volatile int mCapabilities; - private GnssPowerStats mGnssPowerStats; - - /** - * Handles GNSS Power Indication capabilities update from the GNSS HAL callback. - */ - public void onCapabilitiesUpdated(int capabilities) { - mCapabilities = capabilities; - } - - public void onGnssPowerStatsAvailable(GnssPowerStats powerStats) { - if (DEBUG) { - Log.d(TAG, "onGnssPowerStatsAvailable: " + powerStats.toString()); - } - powerStats.validate(); - mGnssPowerStats = powerStats; - } - - /** - * Returns the GNSS Power Indication specific capabilities. - */ - public int getCapabilities() { - return mCapabilities; - } - - /** - * Requests the GNSS HAL to report {@link GnssPowerStats}. - */ - public static void requestPowerStats() { - native_request_power_stats(); - } - - private boolean hasCapability(int capability) { - return (mCapabilities & capability) != 0; - } - - /** - * Dump info for debugging. - */ - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mGnssPowerStats == null) { - return; - } - pw.print("GnssPowerStats["); - if (mGnssPowerStats.hasElapsedRealtimeNanos()) { - pw.print("ElapsedRealtime=" + mGnssPowerStats.getElapsedRealtimeNanos()); - } - if (mGnssPowerStats.hasElapsedRealtimeUncertaintyNanos()) { - pw.print(", ElapsedRealtimeUncertaintyNanos=" - + mGnssPowerStats.getElapsedRealtimeUncertaintyNanos()); - } - if (hasCapability(CAPABILITY_TOTAL)) { - pw.print(", TotalEnergyMilliJoule=" + mGnssPowerStats.getTotalEnergyMilliJoule()); - } - if (hasCapability(CAPABILITY_SINGLEBAND_TRACKING)) { - pw.print(", SinglebandTrackingModeEnergyMilliJoule=" - + mGnssPowerStats.getSinglebandTrackingModeEnergyMilliJoule()); - } - if (hasCapability(CAPABILITY_MULTIBAND_TRACKING)) { - pw.print(", MultibandTrackingModeEnergyMilliJoule=" - + mGnssPowerStats.getMultibandTrackingModeEnergyMilliJoule()); - } - if (hasCapability(CAPABILITY_SINGLEBAND_ACQUISITION)) { - pw.print(", SinglebandAcquisitionModeEnergyMilliJoule=" - + mGnssPowerStats.getSinglebandAcquisitionModeEnergyMilliJoule()); - } - if (hasCapability(CAPABILITY_MULTIBAND_ACQUISITION)) { - pw.print(", MultibandAcquisitionModeEnergyMilliJoule=" - + mGnssPowerStats.getMultibandAcquisitionModeEnergyMilliJoule()); - } - if (hasCapability(CAPABILITY_OTHER_MODES)) { - pw.print(", OtherModesEnergyMilliJoule=["); - double[] otherModes = mGnssPowerStats.getOtherModesEnergyMilliJoule(); - for (int i = 0; i < otherModes.length; i++) { - pw.print(otherModes[i]); - if (i < otherModes.length - 1) { - pw.print(", "); - } - } - pw.print("] "); - } - pw.println(']'); - } - - private static native void native_request_power_stats(); -} diff --git a/services/core/java/com/android/server/location/gnss/GnssPowerStats.java b/services/core/java/com/android/server/location/gnss/GnssPowerStats.java index b924d1fd98b28..924ffe10be7b0 100644 --- a/services/core/java/com/android/server/location/gnss/GnssPowerStats.java +++ b/services/core/java/com/android/server/location/gnss/GnssPowerStats.java @@ -19,13 +19,23 @@ package com.android.server.location.gnss; import static android.hardware.gnss.ElapsedRealtime.HAS_TIMESTAMP_NS; import static android.hardware.gnss.ElapsedRealtime.HAS_TIME_UNCERTAINTY_NS; +import static java.util.concurrent.TimeUnit.NANOSECONDS; + +import android.location.GnssCapabilities; +import android.util.IndentingPrintWriter; +import android.util.TimeUtils; + import com.android.internal.util.Preconditions; +import com.android.server.location.gnss.hal.GnssNative.GnssRealtimeFlags; + +import java.io.FileDescriptor; /** * Represents Cumulative GNSS power statistics since boot. */ -class GnssPowerStats { - private final int mElapsedRealtimeFlags; +public class GnssPowerStats { + + private final @GnssRealtimeFlags int mElapsedRealtimeFlags; private final long mElapsedRealtimeNanos; private final double mElapsedRealtimeUncertaintyNanos; private final double mTotalEnergyMilliJoule; @@ -35,7 +45,7 @@ class GnssPowerStats { private final double mMultibandAcquisitionModeEnergyMilliJoule; private final double[] mOtherModesEnergyMilliJoule; - GnssPowerStats(int elapsedRealtimeFlags, + public GnssPowerStats(@GnssRealtimeFlags int elapsedRealtimeFlags, long elapsedRealtimeNanos, double elapsedRealtimeUncertaintyNanos, double totalEnergyMilliJoule, @@ -131,4 +141,51 @@ class GnssPowerStats { public void validate() { Preconditions.checkArgument(hasElapsedRealtimeNanos()); } + + /** + * Dumps power stat information filtered by the given capabilities. + */ + public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args, + GnssCapabilities capabilities) { + if (hasElapsedRealtimeNanos()) { + ipw.print("time: "); + ipw.print(TimeUtils.formatRealtime(NANOSECONDS.toMillis(mElapsedRealtimeNanos))); + if (hasElapsedRealtimeUncertaintyNanos() && mElapsedRealtimeUncertaintyNanos != 0) { + ipw.print(" +/- "); + ipw.print(NANOSECONDS.toMillis((long) mElapsedRealtimeUncertaintyNanos)); + } + } + if (capabilities.hasPowerTotal()) { + ipw.print("total power: "); + ipw.print(mTotalEnergyMilliJoule); + ipw.println("mJ"); + } + if (capabilities.hasPowerSinglebandTracking()) { + ipw.print("single-band tracking power: "); + ipw.print(mSinglebandTrackingModeEnergyMilliJoule); + ipw.println("mJ"); + } + if (capabilities.hasPowerMultibandTracking()) { + ipw.print("multi-band tracking power: "); + ipw.print(mMultibandTrackingModeEnergyMilliJoule); + ipw.println("mJ"); + } + if (capabilities.hasPowerSinglebandAcquisition()) { + ipw.print("single-band acquisition power: "); + ipw.print(mSinglebandAcquisitionModeEnergyMilliJoule); + ipw.println("mJ"); + } + if (capabilities.hasPowerMultibandAcquisition()) { + ipw.print("multi-band acquisition power: "); + ipw.print(mMultibandAcquisitionModeEnergyMilliJoule); + ipw.println("mJ"); + } + if (capabilities.hasPowerOtherModes()) { + for (int i = 1; i <= mOtherModesEnergyMilliJoule.length; i++) { + ipw.print("other mode [" + i + "] power: "); + ipw.print(mOtherModesEnergyMilliJoule[i]); + ipw.println("mJ"); + } + } + } } diff --git a/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java b/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java index 49aa235926e94..e0673db274e57 100644 --- a/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java @@ -20,6 +20,7 @@ import static com.android.server.location.gnss.GnssManagerService.D; import static com.android.server.location.gnss.GnssManagerService.TAG; import android.app.AppOpsManager; +import android.location.GnssCapabilities; import android.location.GnssStatus; import android.location.IGnssStatusListener; import android.location.util.identity.CallerIdentity; @@ -27,6 +28,7 @@ import android.os.IBinder; import android.stats.location.LocationStatsEnums; import android.util.Log; +import com.android.server.location.gnss.hal.GnssNative; import com.android.server.location.injector.AppOpsHelper; import com.android.server.location.injector.Injector; import com.android.server.location.injector.LocationUsageLogger; @@ -36,15 +38,23 @@ import java.util.Collection; /** * Implementation of a handler for {@link IGnssStatusListener}. */ -public class GnssStatusProvider extends GnssListenerMultiplexer { +public class GnssStatusProvider extends + GnssListenerMultiplexer implements + GnssNative.BaseCallbacks, GnssNative.StatusCallbacks, GnssNative.SvStatusCallbacks { private final AppOpsHelper mAppOpsHelper; private final LocationUsageLogger mLogger; - public GnssStatusProvider(Injector injector) { + private boolean mIsNavigating = false; + + public GnssStatusProvider(Injector injector, GnssNative gnssNative) { super(injector); mAppOpsHelper = injector.getAppOpsHelper(); mLogger = injector.getLocationUsageLogger(); + + gnssNative.addBaseCallbacks(this); + gnssNative.addStatusCallbacks(this); + gnssNative.addSvStatusCallbacks(this); } @Override @@ -95,30 +105,50 @@ public class GnssStatusProvider extends GnssListenerMultiplexer { listener.onFirstFix(ttff); }); } - /** - * Called by GnssLocationProvider. - */ - public void onSvStatusChanged(GnssStatus gnssStatus) { + @Override + public void onReportSvStatus(GnssStatus gnssStatus) { deliverToListeners(registration -> { if (mAppOpsHelper.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION, registration.getIdentity())) { @@ -128,18 +158,4 @@ public class GnssStatusProvider extends GnssListenerMultiplexer { - if (mAppOpsHelper.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION, - registration.getIdentity())) { - return listener -> listener.onNmeaReceived(timestamp, nmea); - } else { - return null; - } - }); - } } diff --git a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java new file mode 100644 index 0000000000000..89d82495dca30 --- /dev/null +++ b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java @@ -0,0 +1,1490 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.location.gnss.hal; + +import static com.android.server.location.gnss.GnssManagerService.TAG; + +import android.annotation.IntDef; +import android.annotation.Nullable; +import android.location.GnssAntennaInfo; +import android.location.GnssCapabilities; +import android.location.GnssMeasurementCorrections; +import android.location.GnssMeasurementsEvent; +import android.location.GnssNavigationMessage; +import android.location.GnssStatus; +import android.location.Location; +import android.os.SystemClock; +import android.util.Log; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.Preconditions; +import com.android.server.FgThread; +import com.android.server.location.gnss.GnssConfiguration; +import com.android.server.location.gnss.GnssPowerStats; +import com.android.server.location.injector.EmergencyHelper; +import com.android.server.location.injector.Injector; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.List; +import java.util.Objects; + +/** + * Entry point for most GNSS HAL commands and callbacks. + */ +public class GnssNative { + + // IMPORTANT - must match GnssPositionMode enum in IGnss.hal + public static final int GNSS_POSITION_MODE_STANDALONE = 0; + public static final int GNSS_POSITION_MODE_MS_BASED = 1; + public static final int GNSS_POSITION_MODE_MS_ASSISTED = 2; + + @IntDef(prefix = "GNSS_POSITION_MODE_", value = {GNSS_POSITION_MODE_STANDALONE, + GNSS_POSITION_MODE_MS_BASED, GNSS_POSITION_MODE_MS_ASSISTED}) + @Retention(RetentionPolicy.SOURCE) + public @interface GnssPositionMode {} + + // IMPORTANT - must match GnssPositionRecurrence enum in IGnss.hal + public static final int GNSS_POSITION_RECURRENCE_PERIODIC = 0; + public static final int GNSS_POSITION_RECURRENCE_SINGLE = 1; + + @IntDef(prefix = "GNSS_POSITION_RECURRENCE_", value = {GNSS_POSITION_RECURRENCE_PERIODIC, + GNSS_POSITION_RECURRENCE_SINGLE}) + @Retention(RetentionPolicy.SOURCE) + public @interface GnssPositionRecurrence {} + + // IMPORTANT - must match the GnssLocationFlags enum in types.hal + public static final int GNSS_LOCATION_HAS_LAT_LONG = 1; + public static final int GNSS_LOCATION_HAS_ALTITUDE = 2; + public static final int GNSS_LOCATION_HAS_SPEED = 4; + public static final int GNSS_LOCATION_HAS_BEARING = 8; + public static final int GNSS_LOCATION_HAS_HORIZONTAL_ACCURACY = 16; + public static final int GNSS_LOCATION_HAS_VERTICAL_ACCURACY = 32; + public static final int GNSS_LOCATION_HAS_SPEED_ACCURACY = 64; + public static final int GNSS_LOCATION_HAS_BEARING_ACCURACY = 128; + + @IntDef(flag = true, prefix = "GNSS_LOCATION_", value = {GNSS_LOCATION_HAS_LAT_LONG, + GNSS_LOCATION_HAS_ALTITUDE, GNSS_LOCATION_HAS_SPEED, GNSS_LOCATION_HAS_BEARING, + GNSS_LOCATION_HAS_HORIZONTAL_ACCURACY, GNSS_LOCATION_HAS_VERTICAL_ACCURACY, + GNSS_LOCATION_HAS_SPEED_ACCURACY, GNSS_LOCATION_HAS_BEARING_ACCURACY}) + @Retention(RetentionPolicy.SOURCE) + public @interface GnssLocationFlags {} + + // IMPORTANT - must match the ElapsedRealtimeFlags enum in types.hal + public static final int GNSS_REALTIME_HAS_TIMESTAMP_NS = 1; + public static final int GNSS_REALTIME_HAS_TIME_UNCERTAINTY_NS = 2; + + @IntDef(flag = true, value = {GNSS_REALTIME_HAS_TIMESTAMP_NS, + GNSS_REALTIME_HAS_TIME_UNCERTAINTY_NS}) + @Retention(RetentionPolicy.SOURCE) + public @interface GnssRealtimeFlags {} + + // IMPORTANT - must match the GnssAidingData enum in IGnss.hal + public static final int GNSS_AIDING_TYPE_EPHEMERIS = 0x0001; + public static final int GNSS_AIDING_TYPE_ALMANAC = 0x0002; + public static final int GNSS_AIDING_TYPE_POSITION = 0x0004; + public static final int GNSS_AIDING_TYPE_TIME = 0x0008; + public static final int GNSS_AIDING_TYPE_IONO = 0x0010; + public static final int GNSS_AIDING_TYPE_UTC = 0x0020; + public static final int GNSS_AIDING_TYPE_HEALTH = 0x0040; + public static final int GNSS_AIDING_TYPE_SVDIR = 0x0080; + public static final int GNSS_AIDING_TYPE_SVSTEER = 0x0100; + public static final int GNSS_AIDING_TYPE_SADATA = 0x0200; + public static final int GNSS_AIDING_TYPE_RTI = 0x0400; + public static final int GNSS_AIDING_TYPE_CELLDB_INFO = 0x8000; + public static final int GNSS_AIDING_TYPE_ALL = 0xFFFF; + + @IntDef(flag = true, prefix = "GNSS_AIDING_", value = {GNSS_AIDING_TYPE_EPHEMERIS, + GNSS_AIDING_TYPE_ALMANAC, GNSS_AIDING_TYPE_POSITION, GNSS_AIDING_TYPE_TIME, + GNSS_AIDING_TYPE_IONO, GNSS_AIDING_TYPE_UTC, GNSS_AIDING_TYPE_HEALTH, + GNSS_AIDING_TYPE_SVDIR, GNSS_AIDING_TYPE_SVSTEER, GNSS_AIDING_TYPE_SADATA, + GNSS_AIDING_TYPE_RTI, GNSS_AIDING_TYPE_CELLDB_INFO, GNSS_AIDING_TYPE_ALL}) + @Retention(RetentionPolicy.SOURCE) + public @interface GnssAidingTypeFlags {} + + // IMPORTANT - must match OEM definitions, this isn't part of a hal for some reason + public static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1; + public static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2; + + @IntDef(prefix = "AGPS_REF_LOCATION_TYPE_", value = {AGPS_REF_LOCATION_TYPE_GSM_CELLID, + AGPS_REF_LOCATION_TYPE_UMTS_CELLID}) + @Retention(RetentionPolicy.SOURCE) + public @interface AgpsReferenceLocationType {} + + // IMPORTANT - must match OEM definitions, this isn't part of a hal for some reason + public static final int AGPS_SETID_TYPE_NONE = 0; + public static final int AGPS_SETID_TYPE_IMSI = 1; + public static final int AGPS_SETID_TYPE_MSISDN = 2; + + @IntDef(prefix = "AGPS_SETID_TYPE_", value = {AGPS_SETID_TYPE_NONE, AGPS_SETID_TYPE_IMSI, + AGPS_SETID_TYPE_MSISDN}) + @Retention(RetentionPolicy.SOURCE) + public @interface AgpsSetIdType {} + + /** Callbacks relevant to the entire HAL. */ + public interface BaseCallbacks { + void onHalRestarted(); + void onCapabilitiesChanged(GnssCapabilities oldCapabilities, + GnssCapabilities newCapabilities); + } + + /** Callbacks for status events. */ + public interface StatusCallbacks { + + // IMPORTANT - must match GnssStatusValue enum in IGnssCallback.hal + int GNSS_STATUS_NONE = 0; + int GNSS_STATUS_SESSION_BEGIN = 1; + int GNSS_STATUS_SESSION_END = 2; + int GNSS_STATUS_ENGINE_ON = 3; + int GNSS_STATUS_ENGINE_OFF = 4; + + @IntDef(prefix = "GNSS_STATUS_", value = {GNSS_STATUS_NONE, GNSS_STATUS_SESSION_BEGIN, + GNSS_STATUS_SESSION_END, GNSS_STATUS_ENGINE_ON, GNSS_STATUS_ENGINE_OFF}) + @Retention(RetentionPolicy.SOURCE) + @interface GnssStatusValue {} + + void onReportStatus(@GnssStatusValue int status); + void onReportFirstFix(int ttff); + } + + /** Callbacks for SV status events. */ + public interface SvStatusCallbacks { + void onReportSvStatus(GnssStatus gnssStatus); + } + + /** Callbacks for NMEA events. */ + public interface NmeaCallbacks { + void onReportNmea(long timestamp); + } + + /** Callbacks for location events. */ + public interface LocationCallbacks { + void onReportLocation(boolean hasLatLong, Location location); + void onReportLocations(Location[] locations); + } + + /** Callbacks for measurement events. */ + public interface MeasurementCallbacks { + void onReportMeasurements(GnssMeasurementsEvent event); + } + + /** Callbacks for antenna info events. */ + public interface AntennaInfoCallbacks { + void onReportAntennaInfo(List antennaInfos); + } + + /** Callbacks for navigation message events. */ + public interface NavigationMessageCallbacks { + void onReportNavigationMessage(GnssNavigationMessage event); + } + + /** Callbacks for geofence events. */ + public interface GeofenceCallbacks { + + // IMPORTANT - must match GeofenceTransition enum in IGnssGeofenceCallback.hal + int GEOFENCE_TRANSITION_ENTERED = 1 << 0L; + int GEOFENCE_TRANSITION_EXITED = 1 << 1L; + int GEOFENCE_TRANSITION_UNCERTAIN = 1 << 2L; + + @IntDef(prefix = "GEOFENCE_TRANSITION_", value = {GEOFENCE_TRANSITION_ENTERED, + GEOFENCE_TRANSITION_EXITED, GEOFENCE_TRANSITION_UNCERTAIN}) + @Retention(RetentionPolicy.SOURCE) + @interface GeofenceTransition {} + + // IMPORTANT - must match GeofenceAvailability enum in IGnssGeofenceCallback.hal + int GEOFENCE_AVAILABILITY_UNAVAILABLE = 1 << 0L; + int GEOFENCE_AVAILABILITY_AVAILABLE = 1 << 1L; + + @IntDef(prefix = "GEOFENCE_AVAILABILITY_", value = {GEOFENCE_AVAILABILITY_UNAVAILABLE, + GEOFENCE_AVAILABILITY_AVAILABLE}) + @Retention(RetentionPolicy.SOURCE) + @interface GeofenceAvailability {} + + // IMPORTANT - must match GeofenceStatus enum in IGnssGeofenceCallback.hal + int GEOFENCE_STATUS_OPERATION_SUCCESS = 0; + int GEOFENCE_STATUS_ERROR_TOO_MANY_GEOFENCES = 100; + int GEOFENCE_STATUS_ERROR_ID_EXISTS = -101; + int GEOFENCE_STATUS_ERROR_ID_UNKNOWN = -102; + int GEOFENCE_STATUS_ERROR_INVALID_TRANSITION = -103; + int GEOFENCE_STATUS_ERROR_GENERIC = -149; + + @IntDef(prefix = "GEOFENCE_STATUS_", value = {GEOFENCE_STATUS_OPERATION_SUCCESS, + GEOFENCE_STATUS_ERROR_TOO_MANY_GEOFENCES, GEOFENCE_STATUS_ERROR_ID_EXISTS, + GEOFENCE_STATUS_ERROR_ID_UNKNOWN, GEOFENCE_STATUS_ERROR_INVALID_TRANSITION, + GEOFENCE_STATUS_ERROR_GENERIC}) + @Retention(RetentionPolicy.SOURCE) + @interface GeofenceStatus {} + + void onReportGeofenceTransition(int geofenceId, Location location, + @GeofenceTransition int transition, long timestamp); + void onReportGeofenceStatus(@GeofenceAvailability int availabilityStatus, + Location location); + void onReportGeofenceAddStatus(int geofenceId, @GeofenceStatus int status); + void onReportGeofenceRemoveStatus(int geofenceId, @GeofenceStatus int status); + void onReportGeofencePauseStatus(int geofenceId, @GeofenceStatus int status); + void onReportGeofenceResumeStatus(int geofenceId, @GeofenceStatus int status); + } + + /** Callbacks for the HAL requesting time. */ + public interface TimeCallbacks { + void onRequestUtcTime(); + } + + /** Callbacks for the HAL requesting locations. */ + public interface LocationRequestCallbacks { + void onRequestLocation(boolean independentFromGnss, boolean isUserEmergency); + void onRequestRefLocation(); + } + + /** Callbacks for HAL requesting PSDS download. */ + public interface PsdsCallbacks { + void onRequestPsdsDownload(int psdsType); + } + + /** Callbacks for AGPS functionality. */ + public interface AGpsCallbacks { + + // IMPORTANT - must match OEM definitions, this isn't part of a hal for some reason + int AGPS_REQUEST_SETID_IMSI = 1 << 0L; + int AGPS_REQUEST_SETID_MSISDN = 1 << 1L; + + @IntDef(flag = true, prefix = "AGPS_REQUEST_SETID_", value = {AGPS_REQUEST_SETID_IMSI, + AGPS_REQUEST_SETID_MSISDN}) + @Retention(RetentionPolicy.SOURCE) + @interface AgpsSetIdFlags {} + + void onReportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr); + void onRequestSetID(@AgpsSetIdFlags int flags); + } + + /** Callbacks for notifications. */ + public interface NotificationCallbacks { + void onReportNiNotification(int notificationId, int niType, int notifyFlags, + int timeout, int defaultResponse, String requestorId, String text, + int requestorIdEncoding, int textEncoding); + void onReportNfwNotification(String proxyAppPackageName, byte protocolStack, + String otherProtocolStackName, byte requestor, String requestorId, + byte responseType, boolean inEmergencyMode, boolean isCachedLocation); + } + + // set lower than the current ITAR limit of 600m/s to allow this to trigger even if GPS HAL + // stops output right at 600m/s, depriving this of the information of a device that reaches + // greater than 600m/s, and higher than the speed of sound to avoid impacting most use cases. + private static final float ITAR_SPEED_LIMIT_METERS_PER_SECOND = 400.0f; + + /** + * Indicates that this method is a native entry point. Useful purely for IDEs which can + * understand entry points, and thus eliminate incorrect warnings about methods not used. + */ + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.SOURCE) + private @interface NativeEntryPoint {} + + @GuardedBy("GnssNative.class") + private static GnssHal sGnssHal; + + @GuardedBy("GnssNative.class") + private static boolean sGnssHalInitialized; + + @GuardedBy("GnssNative.class") + private static GnssNative sInstance; + + /** + * Sets GnssHal instance to use for testing. + */ + @VisibleForTesting + public static synchronized void setGnssHalForTest(GnssHal gnssHal) { + sGnssHal = Objects.requireNonNull(gnssHal); + sGnssHalInitialized = false; + sInstance = null; + } + + private static synchronized void initializeHal() { + if (!sGnssHalInitialized) { + if (sGnssHal == null) { + sGnssHal = new GnssHal(); + } + sGnssHal.classInitOnce(); + sGnssHalInitialized = true; + } + } + + /** + * Returns true if GNSS is supported on this device. If true, then + * {@link #create(Injector, GnssConfiguration)} may be invoked. + */ + public static synchronized boolean isSupported() { + initializeHal(); + return sGnssHal.isSupported(); + } + + /** + * Creates a new instance of GnssNative. Should only be invoked if {@link #isSupported()} is + * true. May only be invoked once. + */ + public static synchronized GnssNative create(Injector injector, + GnssConfiguration configuration) { + // side effect - ensures initialization + Preconditions.checkState(isSupported()); + Preconditions.checkState(sInstance == null); + return (sInstance = new GnssNative(sGnssHal, injector, configuration)); + } + + private final GnssHal mGnssHal; + private final EmergencyHelper mEmergencyHelper; + private final GnssConfiguration mConfiguration; + + // these callbacks may have multiple implementations + private BaseCallbacks[] mBaseCallbacks = new BaseCallbacks[0]; + private StatusCallbacks[] mStatusCallbacks = new StatusCallbacks[0]; + private SvStatusCallbacks[] mSvStatusCallbacks = new SvStatusCallbacks[0]; + private NmeaCallbacks[] mNmeaCallbacks = new NmeaCallbacks[0]; + private LocationCallbacks[] mLocationCallbacks = new LocationCallbacks[0]; + private MeasurementCallbacks[] mMeasurementCallbacks = new MeasurementCallbacks[0]; + private AntennaInfoCallbacks[] mAntennaInfoCallbacks = new AntennaInfoCallbacks[0]; + private NavigationMessageCallbacks[] mNavigationMessageCallbacks = + new NavigationMessageCallbacks[0]; + + // these callbacks may only have a single implementation + private GeofenceCallbacks mGeofenceCallbacks; + private TimeCallbacks mTimeCallbacks; + private LocationRequestCallbacks mLocationRequestCallbacks; + private PsdsCallbacks mPsdsCallbacks; + private AGpsCallbacks mAGpsCallbacks; + private NotificationCallbacks mNotificationCallbacks; + + private boolean mRegistered; + + private volatile boolean mItarSpeedLimitExceeded; + + private GnssCapabilities mCapabilities = new GnssCapabilities.Builder().build(); + private @Nullable GnssPowerStats mPowerStats = null; + private int mHardwareYear = 0; + private @Nullable String mHardwareModelName = null; + private long mStartRealtimeMs = 0; + private boolean mHasFirstFix = false; + + private GnssNative(GnssHal gnssHal, Injector injector, GnssConfiguration configuration) { + mGnssHal = Objects.requireNonNull(gnssHal); + mEmergencyHelper = injector.getEmergencyHelper(); + mConfiguration = configuration; + } + + public void addBaseCallbacks(BaseCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + mBaseCallbacks = ArrayUtils.appendElement(BaseCallbacks.class, mBaseCallbacks, callbacks); + } + + public void addStatusCallbacks(StatusCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + mStatusCallbacks = ArrayUtils.appendElement(StatusCallbacks.class, mStatusCallbacks, + callbacks); + } + + public void addSvStatusCallbacks(SvStatusCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + mSvStatusCallbacks = ArrayUtils.appendElement(SvStatusCallbacks.class, mSvStatusCallbacks, + callbacks); + } + + public void addNmeaCallbacks(NmeaCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + mNmeaCallbacks = ArrayUtils.appendElement(NmeaCallbacks.class, mNmeaCallbacks, + callbacks); + } + + public void addLocationCallbacks(LocationCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + mLocationCallbacks = ArrayUtils.appendElement(LocationCallbacks.class, mLocationCallbacks, + callbacks); + } + + public void addMeasurementCallbacks(MeasurementCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + mMeasurementCallbacks = ArrayUtils.appendElement(MeasurementCallbacks.class, + mMeasurementCallbacks, callbacks); + } + + public void addAntennaInfoCallbacks(AntennaInfoCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + mAntennaInfoCallbacks = ArrayUtils.appendElement(AntennaInfoCallbacks.class, + mAntennaInfoCallbacks, callbacks); + } + + public void addNavigationMessageCallbacks(NavigationMessageCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + mNavigationMessageCallbacks = ArrayUtils.appendElement(NavigationMessageCallbacks.class, + mNavigationMessageCallbacks, callbacks); + } + + public void setGeofenceCallbacks(GeofenceCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + Preconditions.checkState(mGeofenceCallbacks == null); + mGeofenceCallbacks = Objects.requireNonNull(callbacks); + } + + public void setTimeCallbacks(TimeCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + Preconditions.checkState(mTimeCallbacks == null); + mTimeCallbacks = Objects.requireNonNull(callbacks); + } + + public void setLocationRequestCallbacks(LocationRequestCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + Preconditions.checkState(mLocationRequestCallbacks == null); + mLocationRequestCallbacks = Objects.requireNonNull(callbacks); + } + + public void setPsdsCallbacks(PsdsCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + Preconditions.checkState(mPsdsCallbacks == null); + mPsdsCallbacks = Objects.requireNonNull(callbacks); + } + + public void setAGpsCallbacks(AGpsCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + Preconditions.checkState(mAGpsCallbacks == null); + mAGpsCallbacks = Objects.requireNonNull(callbacks); + } + + public void setNotificationCallbacks(NotificationCallbacks callbacks) { + Preconditions.checkState(!mRegistered); + Preconditions.checkState(mNotificationCallbacks == null); + mNotificationCallbacks = Objects.requireNonNull(callbacks); + } + + /** + * Registers with the HAL and allows callbacks to begin. Once registered with the native HAL, + * no more callbacks can be added or set. Must only be called once. + */ + public void register() { + Preconditions.checkState(!mRegistered); + mRegistered = true; + + initializeGnss(false); + } + + private void initializeGnss(boolean restart) { + Preconditions.checkState(mRegistered); + mGnssHal.initOnce(GnssNative.this, restart); + + // gnss chipset appears to require an init/cleanup cycle on startup in order to properly + // initialize - undocumented and no idea why this is the case + if (mGnssHal.init()) { + mGnssHal.cleanup(); + Log.i(TAG, "gnss hal initialized"); + } else { + Log.e(TAG, "gnss hal initialization failed"); + } + } + + public GnssConfiguration getConfiguration() { + return mConfiguration; + } + + /** + * Starts up GNSS HAL, and has undocumented side effect of informing HAL that location is + * allowed by settings. + */ + public boolean init() { + Preconditions.checkState(mRegistered); + return mGnssHal.init(); + } + + /** + * Shuts down GNSS HAL, and has undocumented side effect of informing HAL that location is not + * allowed by settings. + */ + public void cleanup() { + Preconditions.checkState(mRegistered); + mGnssHal.cleanup(); + } + + /** + * Returns the latest power stats from the GNSS HAL. + */ + public @Nullable GnssPowerStats getPowerStats() { + return mPowerStats; + } + + /** + * Returns current capabilities of the GNSS HAL. + */ + public GnssCapabilities getCapabilities() { + return mCapabilities; + } + + /** + * Returns hardware year of GNSS chipset. + */ + public int getHardwareYear() { + return mHardwareYear; + } + + /** + * Returns hardware model name of GNSS chipset. + */ + public @Nullable String getHardwareModelName() { + return mHardwareModelName; + } + + /** + * Returns true if the ITAR speed limit is currently being exceeded, and thus location + * information may be blocked. + */ + public boolean isItarSpeedLimitExceeded() { + return mItarSpeedLimitExceeded; + } + + /** + * Starts the GNSS HAL. + */ + public boolean start() { + Preconditions.checkState(mRegistered); + mStartRealtimeMs = SystemClock.elapsedRealtime(); + mHasFirstFix = false; + return mGnssHal.start(); + } + + /** + * Stops the GNSS HAL. + */ + public boolean stop() { + Preconditions.checkState(mRegistered); + return mGnssHal.stop(); + } + + /** + * Sets the position mode. + */ + public boolean setPositionMode(@GnssPositionMode int mode, + @GnssPositionRecurrence int recurrence, int minInterval, int preferredAccuracy, + int preferredTime, boolean lowPowerMode) { + Preconditions.checkState(mRegistered); + return mGnssHal.setPositionMode(mode, recurrence, minInterval, preferredAccuracy, + preferredTime, lowPowerMode); + } + + /** + * Returns a debug string from the GNSS HAL. + */ + public String getInternalState() { + Preconditions.checkState(mRegistered); + return mGnssHal.getInternalState(); + } + + /** + * Deletes any aiding data specified by the given flags. + */ + public void deleteAidingData(@GnssAidingTypeFlags int flags) { + Preconditions.checkState(mRegistered); + mGnssHal.deleteAidingData(flags); + } + + /** + * Reads an NMEA message into the given buffer, returning the number of bytes loaded into the + * buffer. + */ + public int readNmea(byte[] buffer, int bufferSize) { + Preconditions.checkState(mRegistered); + return mGnssHal.readNmea(buffer, bufferSize); + } + + /** + * Injects location information into the GNSS HAL. + */ + public void injectLocation(Location location) { + Preconditions.checkState(mRegistered); + if (location.hasAccuracy()) { + mGnssHal.injectLocation(location.getLatitude(), location.getLongitude(), + location.getAccuracy()); + } + } + + /** + * Injects a location into the GNSS HAL in response to a HAL request for location. + */ + public void injectBestLocation(Location location) { + Preconditions.checkState(mRegistered); + + int gnssLocationFlags = GNSS_LOCATION_HAS_LAT_LONG + | (location.hasAltitude() ? GNSS_LOCATION_HAS_ALTITUDE : 0) + | (location.hasSpeed() ? GNSS_LOCATION_HAS_SPEED : 0) + | (location.hasBearing() ? GNSS_LOCATION_HAS_BEARING : 0) + | (location.hasAccuracy() ? GNSS_LOCATION_HAS_HORIZONTAL_ACCURACY : 0) + | (location.hasVerticalAccuracy() ? GNSS_LOCATION_HAS_VERTICAL_ACCURACY : 0) + | (location.hasSpeedAccuracy() ? GNSS_LOCATION_HAS_SPEED_ACCURACY : 0) + | (location.hasBearingAccuracy() ? GNSS_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(); + + int elapsedRealtimeFlags = GNSS_REALTIME_HAS_TIMESTAMP_NS + | (location.hasElapsedRealtimeUncertaintyNanos() + ? GNSS_REALTIME_HAS_TIME_UNCERTAINTY_NS : 0); + long elapsedRealtimeNanos = location.getElapsedRealtimeNanos(); + double elapsedRealtimeUncertaintyNanos = location.getElapsedRealtimeUncertaintyNanos(); + + mGnssHal.injectBestLocation(gnssLocationFlags, latitudeDegrees, longitudeDegrees, + altitudeMeters, speedMetersPerSec, bearingDegrees, horizontalAccuracyMeters, + verticalAccuracyMeters, speedAccuracyMetersPerSecond, bearingAccuracyDegrees, + timestamp, elapsedRealtimeFlags, elapsedRealtimeNanos, + elapsedRealtimeUncertaintyNanos); + } + + /** + * Injects time information into the GNSS HAL. + */ + public void injectTime(long time, long timeReference, int uncertainty) { + Preconditions.checkState(mRegistered); + mGnssHal.injectTime(time, timeReference, uncertainty); + } + + /** + * Returns true if navigation message collection is supported. + */ + public boolean isNavigationMessageCollectionSupported() { + Preconditions.checkState(mRegistered); + return mGnssHal.isNavigationMessageCollectionSupported(); + } + + /** + * Starts navigation message collection. + */ + public boolean startNavigationMessageCollection() { + Preconditions.checkState(mRegistered); + return mGnssHal.startNavigationMessageCollection(); + } + + /** + * Stops navigation message collection. + */ + public boolean stopNavigationMessageCollection() { + Preconditions.checkState(mRegistered); + return mGnssHal.stopNavigationMessageCollection(); + } + + /** + * Returns true if antenna info listening is supported. + */ + public boolean isAntennaInfoListeningSupported() { + Preconditions.checkState(mRegistered); + return mGnssHal.isAntennaInfoListeningSupported(); + } + + /** + * Starts antenna info listening. + */ + public boolean startAntennaInfoListening() { + Preconditions.checkState(mRegistered); + return mGnssHal.startAntennaInfoListening(); + } + + /** + * Stops antenna info listening. + */ + public boolean stopAntennaInfoListening() { + Preconditions.checkState(mRegistered); + return mGnssHal.stopAntennaInfoListening(); + } + + /** + * Returns true if measurement collection is supported. + */ + public boolean isMeasurementSupported() { + Preconditions.checkState(mRegistered); + return mGnssHal.isMeasurementSupported(); + } + + /** + * Starts measurement collection. + */ + public boolean startMeasurementCollection(boolean enableFullTracking) { + Preconditions.checkState(mRegistered); + return mGnssHal.startMeasurementCollection(enableFullTracking); + } + + /** + * Stops measurement collection. + */ + public boolean stopMeasurementCollection() { + Preconditions.checkState(mRegistered); + return mGnssHal.stopMeasurementCollection(); + } + + /** + * Returns true if measurement corrections are supported. + */ + public boolean isMeasurementCorrectionsSupported() { + Preconditions.checkState(mRegistered); + return mGnssHal.isMeasurementCorrectionsSupported(); + } + + /** + * Injects measurement corrections into the GNSS HAL. + */ + public boolean injectMeasurementCorrections(GnssMeasurementCorrections corrections) { + Preconditions.checkState(mRegistered); + return mGnssHal.injectMeasurementCorrections(corrections); + } + + /** + * Initialize batching. + */ + public boolean initBatching() { + Preconditions.checkState(mRegistered); + return mGnssHal.initBatching(); + } + + /** + * Cleanup batching. + */ + public void cleanupBatching() { + Preconditions.checkState(mRegistered); + mGnssHal.cleanupBatching(); + } + + /** + * Start batching. + */ + public boolean startBatch(long periodNanos, boolean wakeOnFifoFull) { + Preconditions.checkState(mRegistered); + return mGnssHal.startBatch(periodNanos, wakeOnFifoFull); + } + + /** + * Flush batching. + */ + public void flushBatch() { + Preconditions.checkState(mRegistered); + mGnssHal.flushBatch(); + } + + /** + * Stop batching. + */ + public void stopBatch() { + Preconditions.checkState(mRegistered); + mGnssHal.stopBatch(); + } + + /** + * Get current batching size. + */ + public int getBatchSize() { + Preconditions.checkState(mRegistered); + return mGnssHal.getBatchSize(); + } + + /** + * Check if GNSS geofencing is supported. + */ + public boolean isGeofencingSupported() { + Preconditions.checkState(mRegistered); + return mGnssHal.isGeofencingSupported(); + } + + /** + * Add geofence. + */ + public boolean addGeofence(int geofenceId, double latitude, double longitude, double radius, + int lastTransition, int monitorTransitions, int notificationResponsiveness, + int unknownTimer) { + Preconditions.checkState(mRegistered); + return mGnssHal.addGeofence(geofenceId, latitude, longitude, radius, lastTransition, + monitorTransitions, notificationResponsiveness, unknownTimer); + } + + /** + * Resume geofence. + */ + public boolean resumeGeofence(int geofenceId, int monitorTransitions) { + Preconditions.checkState(mRegistered); + return mGnssHal.resumeGeofence(geofenceId, monitorTransitions); + } + + /** + * Pause geofence. + */ + public boolean pauseGeofence(int geofenceId) { + Preconditions.checkState(mRegistered); + return mGnssHal.pauseGeofence(geofenceId); + } + + /** + * Remove geofence. + */ + public boolean removeGeofence(int geofenceId) { + Preconditions.checkState(mRegistered); + return mGnssHal.removeGeofence(geofenceId); + } + + /** + * Returns true if visibility control is supported. + */ + public boolean isGnssVisibilityControlSupported() { + Preconditions.checkState(mRegistered); + return mGnssHal.isGnssVisibilityControlSupported(); + } + + /** + * Send a network initiated respnse. + */ + public void sendNiResponse(int notificationId, int userResponse) { + Preconditions.checkState(mRegistered); + mGnssHal.sendNiResponse(notificationId, userResponse); + } + + /** + * Request an eventual update of GNSS power statistics. + */ + public void requestPowerStats() { + Preconditions.checkState(mRegistered); + mGnssHal.requestPowerStats(); + } + + /** + * Sets AGPS server information. + */ + public void setAgpsServer(int type, String hostname, int port) { + Preconditions.checkState(mRegistered); + mGnssHal.setAgpsServer(type, hostname, port); + } + + /** + * Sets AGPS set id. + */ + public void setAgpsSetId(@AgpsSetIdType int type, String setId) { + Preconditions.checkState(mRegistered); + mGnssHal.setAgpsSetId(type, setId); + } + + /** + * Sets AGPS reference cell id location. + */ + public void setAgpsReferenceLocationCellId(@AgpsReferenceLocationType int type, int mcc, + int mnc, int lac, int cid) { + Preconditions.checkState(mRegistered); + mGnssHal.setAgpsReferenceLocationCellId(type, mcc, mnc, lac, cid); + } + + /** + * Returns true if Predicted Satellite Data Service APIs are supported. + */ + public boolean isPsdsSupported() { + Preconditions.checkState(mRegistered); + return mGnssHal.isPsdsSupported(); + } + + /** + * Injects Predicited Satellite Data Service data into the GNSS HAL. + */ + public void injectPsdsData(byte[] data, int length, int psdsType) { + Preconditions.checkState(mRegistered); + mGnssHal.injectPsdsData(data, length, psdsType); + } + + @NativeEntryPoint + void reportGnssServiceDied() { + Log.e(TAG, "gnss hal died - restarting shortly..."); + + // move to another thread just in case there is some awkward gnss thread dependency with + // the death notification. there shouldn't be, but you never know with gnss... + FgThread.getExecutor().execute(this::restartHal); + } + + @VisibleForTesting + void restartHal() { + initializeGnss(true); + Log.e(TAG, "gnss hal restarted"); + + for (int i = 0; i < mBaseCallbacks.length; i++) { + mBaseCallbacks[i].onHalRestarted(); + } + } + + @NativeEntryPoint + void reportLocation(boolean hasLatLong, Location location) { + if (hasLatLong && !mHasFirstFix) { + mHasFirstFix = true; + + // notify status listeners + int ttff = (int) (SystemClock.elapsedRealtime() - mStartRealtimeMs); + for (int i = 0; i < mStatusCallbacks.length; i++) { + mStatusCallbacks[i].onReportFirstFix(ttff); + } + } + + if (location.hasSpeed()) { + boolean exceeded = location.getSpeed() > ITAR_SPEED_LIMIT_METERS_PER_SECOND; + if (!mItarSpeedLimitExceeded && exceeded) { + Log.w(TAG, "speed nearing ITAR threshold - blocking further GNSS output"); + } else if (mItarSpeedLimitExceeded && !exceeded) { + Log.w(TAG, "speed leaving ITAR threshold - allowing further GNSS output"); + } + mItarSpeedLimitExceeded = exceeded; + } + + if (mItarSpeedLimitExceeded) { + return; + } + + for (int i = 0; i < mLocationCallbacks.length; i++) { + mLocationCallbacks[i].onReportLocation(hasLatLong, location); + } + } + + @NativeEntryPoint + void reportStatus(@StatusCallbacks.GnssStatusValue int gnssStatus) { + for (int i = 0; i < mStatusCallbacks.length; i++) { + mStatusCallbacks[i].onReportStatus(gnssStatus); + } + } + + @NativeEntryPoint + void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0DbHzs, + float[] elevations, float[] azimuths, float[] carrierFrequencies, + float[] basebandCn0DbHzs) { + GnssStatus gnssStatus = GnssStatus.wrap(svCount, svidWithFlags, cn0DbHzs, elevations, + azimuths, carrierFrequencies, basebandCn0DbHzs); + for (int i = 0; i < mSvStatusCallbacks.length; i++) { + mSvStatusCallbacks[i].onReportSvStatus(gnssStatus); + } + } + + @NativeEntryPoint + void reportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) { + mAGpsCallbacks.onReportAGpsStatus(agpsType, agpsStatus, suplIpAddr); + } + + @NativeEntryPoint + void reportNmea(long timestamp) { + if (mItarSpeedLimitExceeded) { + return; + } + + for (int i = 0; i < mNmeaCallbacks.length; i++) { + mNmeaCallbacks[i].onReportNmea(timestamp); + } + } + + @NativeEntryPoint + void reportMeasurementData(GnssMeasurementsEvent event) { + if (mItarSpeedLimitExceeded) { + return; + } + + for (int i = 0; i < mMeasurementCallbacks.length; i++) { + mMeasurementCallbacks[i].onReportMeasurements(event); + } + } + + @NativeEntryPoint + void reportAntennaInfo(List antennaInfos) { + for (int i = 0; i < mAntennaInfoCallbacks.length; i++) { + mAntennaInfoCallbacks[i].onReportAntennaInfo(antennaInfos); + } + } + + @NativeEntryPoint + void reportNavigationMessage(GnssNavigationMessage event) { + if (mItarSpeedLimitExceeded) { + return; + } + + for (int i = 0; i < mNavigationMessageCallbacks.length; i++) { + mNavigationMessageCallbacks[i].onReportNavigationMessage(event); + } + } + + @NativeEntryPoint + void setTopHalCapabilities(@GnssCapabilities.TopHalCapabilityFlags int capabilities) { + GnssCapabilities oldCapabilities = mCapabilities; + mCapabilities = oldCapabilities.withTopHalFlags(capabilities); + onCapabilitiesChanged(oldCapabilities, mCapabilities); + } + + @NativeEntryPoint + void setSubHalMeasurementCorrectionsCapabilities( + @GnssCapabilities.SubHalMeasurementCorrectionsCapabilityFlags int capabilities) { + GnssCapabilities oldCapabilities = mCapabilities; + mCapabilities = oldCapabilities.withSubHalMeasurementCorrectionsFlags(capabilities); + onCapabilitiesChanged(oldCapabilities, mCapabilities); + } + + @NativeEntryPoint + void setSubHalPowerIndicationCapabilities( + @GnssCapabilities.SubHalPowerCapabilityFlags int capabilities) { + GnssCapabilities oldCapabilities = mCapabilities; + mCapabilities = oldCapabilities.withSubHalPowerFlags(capabilities); + onCapabilitiesChanged(oldCapabilities, mCapabilities); + } + + private void onCapabilitiesChanged(GnssCapabilities oldCapabilities, + GnssCapabilities newCapabilities) { + if (newCapabilities.equals(oldCapabilities)) { + return; + } + + Log.i(TAG, "gnss capabilities changed to " + newCapabilities); + + for (int i = 0; i < mBaseCallbacks.length; i++) { + mBaseCallbacks[i].onCapabilitiesChanged(oldCapabilities, newCapabilities); + } + } + + @NativeEntryPoint + void reportGnssPowerStats(GnssPowerStats powerStats) { + mPowerStats = powerStats; + } + + @NativeEntryPoint + void setGnssYearOfHardware(int year) { + mHardwareYear = year; + } + + @NativeEntryPoint + private void setGnssHardwareModelName(String modelName) { + mHardwareModelName = modelName; + } + + @NativeEntryPoint + void reportLocationBatch(Location[] locations) { + for (int i = 0; i < mLocationCallbacks.length; i++) { + mLocationCallbacks[i].onReportLocations(locations); + } + } + + @NativeEntryPoint + void psdsDownloadRequest(int psdsType) { + mPsdsCallbacks.onRequestPsdsDownload(psdsType); + } + + @NativeEntryPoint + void reportGeofenceTransition(int geofenceId, Location location, int transition, + long transitionTimestamp) { + mGeofenceCallbacks.onReportGeofenceTransition(geofenceId, location, transition, + transitionTimestamp); + } + + @NativeEntryPoint + void reportGeofenceStatus(int status, Location location) { + mGeofenceCallbacks.onReportGeofenceStatus(status, location); + } + + @NativeEntryPoint + void reportGeofenceAddStatus(int geofenceId, @GeofenceCallbacks.GeofenceStatus int status) { + mGeofenceCallbacks.onReportGeofenceAddStatus(geofenceId, status); + } + + @NativeEntryPoint + void reportGeofenceRemoveStatus(int geofenceId, @GeofenceCallbacks.GeofenceStatus int status) { + mGeofenceCallbacks.onReportGeofenceRemoveStatus(geofenceId, status); + } + + @NativeEntryPoint + void reportGeofencePauseStatus(int geofenceId, @GeofenceCallbacks.GeofenceStatus int status) { + mGeofenceCallbacks.onReportGeofencePauseStatus(geofenceId, status); + } + + @NativeEntryPoint + void reportGeofenceResumeStatus(int geofenceId, @GeofenceCallbacks.GeofenceStatus int status) { + mGeofenceCallbacks.onReportGeofenceResumeStatus(geofenceId, status); + } + + @NativeEntryPoint + void reportNiNotification(int notificationId, int niType, int notifyFlags, + int timeout, int defaultResponse, String requestorId, String text, + int requestorIdEncoding, int textEncoding) { + mNotificationCallbacks.onReportNiNotification(notificationId, niType, notifyFlags, timeout, + defaultResponse, requestorId, text, requestorIdEncoding, textEncoding); + } + + @NativeEntryPoint + void requestSetID(int flags) { + mAGpsCallbacks.onRequestSetID(flags); + } + + @NativeEntryPoint + void requestLocation(boolean independentFromGnss, boolean isUserEmergency) { + mLocationRequestCallbacks.onRequestLocation(independentFromGnss, isUserEmergency); + } + + @NativeEntryPoint + void requestUtcTime() { + mTimeCallbacks.onRequestUtcTime(); + } + + @NativeEntryPoint + void requestRefLocation() { + mLocationRequestCallbacks.onRequestRefLocation(); + } + + @NativeEntryPoint + void reportNfwNotification(String proxyAppPackageName, byte protocolStack, + String otherProtocolStackName, byte requestor, String requestorId, + byte responseType, boolean inEmergencyMode, boolean isCachedLocation) { + mNotificationCallbacks.onReportNfwNotification(proxyAppPackageName, protocolStack, + otherProtocolStackName, requestor, requestorId, responseType, inEmergencyMode, + isCachedLocation); + } + + @NativeEntryPoint + boolean isInEmergencySession() { + return mEmergencyHelper.isInEmergency(mConfiguration.getEsExtensionSec()); + } + + /** + * Encapsulates actual HAL methods for testing purposes. + */ + @VisibleForTesting + public static class GnssHal { + + protected GnssHal() {} + + protected void classInitOnce() { + native_class_init_once(); + } + + protected boolean isSupported() { + return native_is_supported(); + } + + protected void initOnce(GnssNative gnssNative, boolean reinitializeGnssServiceHandle) { + gnssNative.native_init_once(reinitializeGnssServiceHandle); + } + + protected boolean init() { + return native_init(); + } + + protected void cleanup() { + native_cleanup(); + } + + protected boolean start() { + return native_start(); + } + + protected boolean stop() { + return native_stop(); + } + + protected boolean setPositionMode(@GnssPositionMode int mode, + @GnssPositionRecurrence int recurrence, int minInterval, int preferredAccuracy, + int preferredTime, boolean lowPowerMode) { + return native_set_position_mode(mode, recurrence, minInterval, preferredAccuracy, + preferredTime, lowPowerMode); + } + + protected String getInternalState() { + return native_get_internal_state(); + } + + protected void deleteAidingData(@GnssAidingTypeFlags int flags) { + native_delete_aiding_data(flags); + } + + protected int readNmea(byte[] buffer, int bufferSize) { + return native_read_nmea(buffer, bufferSize); + } + + protected void injectLocation(double latitude, double longitude, float accuracy) { + native_inject_location(latitude, longitude, accuracy); + } + + protected void injectBestLocation(@GnssLocationFlags int gnssLocationFlags, double latitude, + double longitude, double altitude, float speed, float bearing, + float horizontalAccuracy, float verticalAccuracy, float speedAccuracy, + float bearingAccuracy, long timestamp, @GnssRealtimeFlags int elapsedRealtimeFlags, + long elapsedRealtimeNanos, double elapsedRealtimeUncertaintyNanos) { + native_inject_best_location(gnssLocationFlags, latitude, longitude, altitude, speed, + bearing, horizontalAccuracy, verticalAccuracy, speedAccuracy, bearingAccuracy, + timestamp, elapsedRealtimeFlags, elapsedRealtimeNanos, + elapsedRealtimeUncertaintyNanos); + } + + protected void injectTime(long time, long timeReference, int uncertainty) { + native_inject_time(time, timeReference, uncertainty); + } + + protected boolean isNavigationMessageCollectionSupported() { + return native_is_navigation_message_supported(); + } + + protected boolean startNavigationMessageCollection() { + return native_start_navigation_message_collection(); + } + + protected boolean stopNavigationMessageCollection() { + return native_stop_navigation_message_collection(); + } + + protected boolean isAntennaInfoListeningSupported() { + return native_is_antenna_info_supported(); + } + + protected boolean startAntennaInfoListening() { + return native_start_antenna_info_listening(); + } + + protected boolean stopAntennaInfoListening() { + return native_stop_antenna_info_listening(); + } + + protected boolean isMeasurementSupported() { + return native_is_measurement_supported(); + } + + protected boolean startMeasurementCollection(boolean enableFullTracking) { + return native_start_measurement_collection(enableFullTracking); + } + + protected boolean stopMeasurementCollection() { + return native_stop_measurement_collection(); + } + + protected boolean isMeasurementCorrectionsSupported() { + return native_is_measurement_corrections_supported(); + } + + protected boolean injectMeasurementCorrections(GnssMeasurementCorrections corrections) { + return native_inject_measurement_corrections(corrections); + } + + protected int getBatchSize() { + return native_get_batch_size(); + } + + protected boolean initBatching() { + return native_init_batching(); + } + + protected void cleanupBatching() { + native_cleanup_batching(); + } + + protected boolean startBatch(long periodNanos, boolean wakeOnFifoFull) { + return native_start_batch(periodNanos, wakeOnFifoFull); + } + + protected void flushBatch() { + native_flush_batch(); + } + + protected void stopBatch() { + native_stop_batch(); + } + + protected boolean isGeofencingSupported() { + return native_is_geofence_supported(); + } + + protected boolean addGeofence(int geofenceId, double latitude, double longitude, + double radius, int lastTransition, int monitorTransitions, + int notificationResponsiveness, int unknownTimer) { + return native_add_geofence(geofenceId, latitude, longitude, radius, lastTransition, + monitorTransitions, notificationResponsiveness, unknownTimer); + } + + protected boolean resumeGeofence(int geofenceId, int monitorTransitions) { + return native_resume_geofence(geofenceId, monitorTransitions); + } + + protected boolean pauseGeofence(int geofenceId) { + return native_pause_geofence(geofenceId); + } + + protected boolean removeGeofence(int geofenceId) { + return native_remove_geofence(geofenceId); + } + + protected boolean isGnssVisibilityControlSupported() { + return native_is_gnss_visibility_control_supported(); + } + + protected void sendNiResponse(int notificationId, int userResponse) { + native_send_ni_response(notificationId, userResponse); + } + + protected void requestPowerStats() { + native_request_power_stats(); + } + + protected void setAgpsServer(int type, String hostname, int port) { + native_set_agps_server(type, hostname, port); + } + + protected void setAgpsSetId(@AgpsSetIdType int type, String setId) { + native_agps_set_id(type, setId); + } + + protected void setAgpsReferenceLocationCellId(@AgpsReferenceLocationType int type, int mcc, + int mnc, int lac, int cid) { + native_agps_set_ref_location_cellid(type, mcc, mnc, lac, cid); + } + + protected boolean isPsdsSupported() { + return native_supports_psds(); + } + + protected void injectPsdsData(byte[] data, int length, int psdsType) { + native_inject_psds_data(data, length, psdsType); + } + } + + // basic APIs + + private static native void native_class_init_once(); + + private static native boolean native_is_supported(); + + private native void native_init_once(boolean reinitializeGnssServiceHandle); + + private static native boolean native_init(); + + private static native void native_cleanup(); + + private static native boolean native_start(); + + private static native boolean native_stop(); + + private static native boolean native_set_position_mode(int mode, int recurrence, + int minInterval, int preferredAccuracy, int preferredTime, boolean lowPowerMode); + + private static native String native_get_internal_state(); + + private static native void native_delete_aiding_data(int flags); + + // NMEA APIs + + private static native int native_read_nmea(byte[] buffer, int bufferSize); + + // location injection APIs + + private static native void native_inject_location(double latitude, double longitude, + float accuracy); + + + private static 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, int elapsedRealtimeFlags, long elapsedRealtimeNanos, + double elapsedRealtimeUncertaintyNanos); + + // time injection APIs + + private static native void native_inject_time(long time, long timeReference, int uncertainty); + + // navigation message APIs + + private static native boolean native_is_navigation_message_supported(); + + private static native boolean native_start_navigation_message_collection(); + + private static native boolean native_stop_navigation_message_collection(); + + // antenna info APIS + + private static native boolean native_is_antenna_info_supported(); + + private static native boolean native_start_antenna_info_listening(); + + private static native boolean native_stop_antenna_info_listening(); + + // measurement APIs + + private static native boolean native_is_measurement_supported(); + + private static native boolean native_start_measurement_collection(boolean enableFullTracking); + + private static native boolean native_stop_measurement_collection(); + + // measurement corrections APIs + + private static native boolean native_is_measurement_corrections_supported(); + + private static native boolean native_inject_measurement_corrections( + GnssMeasurementCorrections corrections); + + // batching APIs + + private static native boolean native_init_batching(); + + private static native void native_cleanup_batching(); + + private static native boolean native_start_batch(long periodNanos, boolean wakeOnFifoFull); + + private static native void native_flush_batch(); + + private static native boolean native_stop_batch(); + + private static native int native_get_batch_size(); + + // geofence APIs + + private static native boolean native_is_geofence_supported(); + + private static native boolean native_add_geofence(int geofenceId, double latitude, + double longitude, double radius, int lastTransition, int monitorTransitions, + int notificationResponsivenes, int unknownTimer); + + private static native boolean native_resume_geofence(int geofenceId, int monitorTransitions); + + private static native boolean native_pause_geofence(int geofenceId); + + private static native boolean native_remove_geofence(int geofenceId); + + // network initiated (NI) APIs + + private static native boolean native_is_gnss_visibility_control_supported(); + + private static native void native_send_ni_response(int notificationId, int userResponse); + + // power stats APIs + + private static native void native_request_power_stats(); + + // AGPS APIs + + private static native void native_set_agps_server(int type, String hostname, int port); + + private static native void native_agps_set_id(int type, String setid); + + private static native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc, + int lac, int cid); + + // PSDS APIs + + private static native boolean native_supports_psds(); + + private static native void native_inject_psds_data(byte[] data, int length, int psdsType); +} diff --git a/services/core/java/com/android/server/location/injector/EmergencyHelper.java b/services/core/java/com/android/server/location/injector/EmergencyHelper.java new file mode 100644 index 0000000000000..be4bf5083c65b --- /dev/null +++ b/services/core/java/com/android/server/location/injector/EmergencyHelper.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.location.injector; + +/** + * Provides helpers for emergency sessions. + */ +public abstract class EmergencyHelper { + + /** + * Returns true if the device is in an emergency session, or if an emergency session ended + * within the given extension time. + */ + public abstract boolean isInEmergency(long extensionTimeMs); +} diff --git a/services/core/java/com/android/server/location/injector/Injector.java b/services/core/java/com/android/server/location/injector/Injector.java index c42396da95a5f..03938b2b8ba2e 100644 --- a/services/core/java/com/android/server/location/injector/Injector.java +++ b/services/core/java/com/android/server/location/injector/Injector.java @@ -51,6 +51,9 @@ public interface Injector { /** Returns a LocationAttributionHelper. */ LocationAttributionHelper getLocationAttributionHelper(); + /** Returns an EmergencyHelper. */ + EmergencyHelper getEmergencyHelper(); + /** Returns a LocationUsageLogger. */ LocationUsageLogger getLocationUsageLogger(); diff --git a/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java new file mode 100644 index 0000000000000..05d0aefe7c89c --- /dev/null +++ b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.location.injector; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.SystemClock; +import android.telephony.PhoneStateListener; +import android.telephony.TelephonyManager; + +import com.android.server.FgThread; + +import java.util.Objects; + +/** + * Provides helpers for emergency sessions. + */ +public class SystemEmergencyHelper extends EmergencyHelper { + + private final Context mContext; + + private TelephonyManager mTelephonyManager; + + private boolean mIsInEmergencyCall; + private long mEmergencyCallEndRealtimeMs = Long.MIN_VALUE; + + public SystemEmergencyHelper(Context context) { + mContext = context; + } + + /** Called when system is ready. */ + public void onSystemReady() { + if (mTelephonyManager != null) { + return; + } + + mTelephonyManager = Objects.requireNonNull( + mContext.getSystemService(TelephonyManager.class)); + + // TODO: this doesn't account for multisim phones + + mTelephonyManager.registerPhoneStateListener(FgThread.getExecutor(), + new EmergencyCallPhoneStateListener()); + mContext.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (!Intent.ACTION_NEW_OUTGOING_CALL.equals(intent.getAction())) { + return; + } + + mIsInEmergencyCall = mTelephonyManager.isEmergencyNumber( + intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER)); + } + }, new IntentFilter(Intent.ACTION_NEW_OUTGOING_CALL)); + } + + @Override + public boolean isInEmergency(long extensionTimeMs) { + return mIsInEmergencyCall + || ((SystemClock.elapsedRealtime() - mEmergencyCallEndRealtimeMs) < extensionTimeMs) + || mTelephonyManager.getEmergencyCallbackMode() + || mTelephonyManager.isInEmergencySmsMode(); + } + + private class EmergencyCallPhoneStateListener extends PhoneStateListener implements + PhoneStateListener.CallStateChangedListener { + + @Override + public void onCallStateChanged(int state, String incomingNumber) { + if (state == TelephonyManager.CALL_STATE_IDLE) { + if (mIsInEmergencyCall) { + mEmergencyCallEndRealtimeMs = SystemClock.elapsedRealtime(); + mIsInEmergencyCall = false; + } + } + } + } +} diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java index 49cf6f85855dd..858b7624891ac 100644 --- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java +++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java @@ -1357,6 +1357,8 @@ public class LocationProviderManager extends public boolean isEnabled(int userId) { if (userId == UserHandle.USER_NULL) { return false; + } else if (userId == UserHandle.USER_CURRENT) { + return isEnabled(mUserHelper.getCurrentUserId()); } Preconditions.checkArgument(userId >= 0); @@ -1518,6 +1520,9 @@ public class LocationProviderManager extends } } return lastLocation; + } else if (userId == UserHandle.USER_CURRENT) { + return getLastLocationUnsafe(mUserHelper.getCurrentUserId(), permissionLevel, + ignoreLocationSettings, maximumAgeMs); } Preconditions.checkArgument(userId >= 0); @@ -1560,6 +1565,9 @@ public class LocationProviderManager extends setLastLocation(location, runningUserIds[i]); } return; + } else if (userId == UserHandle.USER_CURRENT) { + setLastLocation(location, mUserHelper.getCurrentUserId()); + return; } Preconditions.checkArgument(userId >= 0); diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index 066dbce89ca6e..e3a8bb4e405e7 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -1442,7 +1442,7 @@ struct GnssBatchingCallback_V2_0 : public IGnssBatchingCallback_V2_0 { }; /* Initializes the GNSS service handle. */ -static void android_location_GnssLocationProvider_set_gps_service_handle() { +static void android_location_gnss_hal_GnssNative_set_gps_service_handle() { gnssHalAidl = waitForVintfService(); if (gnssHalAidl != nullptr) { ALOGD("Successfully got GNSS AIDL handle."); @@ -1489,9 +1489,9 @@ static void android_location_GnssLocationProvider_set_gps_service_handle() { } /* One time initialization at system boot */ -static void android_location_GnssNative_class_init_once(JNIEnv* env, jclass clazz) { +static void android_location_gnss_hal_GnssNative_class_init_once(JNIEnv* env, jclass clazz) { // Initialize the top level gnss HAL handle. - android_location_GnssLocationProvider_set_gps_service_handle(); + android_location_gnss_hal_GnssNative_set_gps_service_handle(); // Cache methodIDs and class IDs. method_reportLocation = env->GetMethodID(clazz, "reportLocation", @@ -1655,8 +1655,8 @@ static void android_location_GnssNative_class_init_once(JNIEnv* env, jclass claz } /* Initialization needed at system boot and whenever GNSS service dies. */ -static void android_location_GnssNative_init_once(JNIEnv* env, jobject obj, - jboolean reinitializeGnssServiceHandle) { +static void android_location_gnss_hal_GnssNative_init_once(JNIEnv* env, jobject obj, + jboolean reinitializeGnssServiceHandle) { /* * Save a pointer to JVM. */ @@ -1666,7 +1666,7 @@ static void android_location_GnssNative_init_once(JNIEnv* env, jobject obj, } if (reinitializeGnssServiceHandle) { - android_location_GnssLocationProvider_set_gps_service_handle(); + android_location_gnss_hal_GnssNative_set_gps_service_handle(); } if (gnssHal == nullptr) { @@ -1934,7 +1934,7 @@ static void android_location_GnssNative_init_once(JNIEnv* env, jobject obj, } } -static jboolean android_location_GnssNative_is_supported(JNIEnv* /* env */, jclass /* clazz */) { +static jboolean android_location_gnss_hal_GnssNative_is_supported(JNIEnv* /* env */, jclass) { return (gnssHal != nullptr) ? JNI_TRUE : JNI_FALSE; } @@ -1952,7 +1952,7 @@ static jobject android_location_GnssConfiguration_get_gnss_configuration_version } /* Initialization needed each time the GPS service is shutdown. */ -static jboolean android_location_GnssLocationProvider_init(JNIEnv* /* env */, jobject /* obj */) { +static jboolean android_location_gnss_hal_GnssNative_init(JNIEnv* /* env */, jclass) { /* * This must be set before calling into the HAL library. */ @@ -2087,7 +2087,7 @@ static jboolean android_location_GnssLocationProvider_init(JNIEnv* /* env */, jo return JNI_TRUE; } -static void android_location_GnssLocationProvider_cleanup(JNIEnv* /* env */, jobject /* obj */) { +static void android_location_gnss_hal_GnssNative_cleanup(JNIEnv* /* env */, jclass) { if (gnssHal == nullptr) { return; } @@ -2096,9 +2096,9 @@ static void android_location_GnssLocationProvider_cleanup(JNIEnv* /* env */, job checkHidlReturn(result, "IGnss cleanup() failed."); } -static jboolean android_location_GnssLocationProvider_set_position_mode(JNIEnv* /* env */, - jobject /* obj */, jint mode, jint recurrence, jint min_interval, jint preferred_accuracy, - jint preferred_time, jboolean low_power_mode) { +static jboolean android_location_gnss_hal_GnssNative_set_position_mode( + JNIEnv* /* env */, jclass, jint mode, jint recurrence, jint min_interval, + jint preferred_accuracy, jint preferred_time, jboolean low_power_mode) { Return result = false; if (gnssHal_V1_1 != nullptr) { result = gnssHal_V1_1->setPositionMode_1_1(static_cast(mode), @@ -2118,7 +2118,7 @@ static jboolean android_location_GnssLocationProvider_set_position_mode(JNIEnv* return checkHidlReturn(result, "IGnss setPositionMode() failed."); } -static jboolean android_location_GnssLocationProvider_start(JNIEnv* /* env */, jobject /* obj */) { +static jboolean android_location_gnss_hal_GnssNative_start(JNIEnv* /* env */, jclass) { if (gnssHal == nullptr) { return JNI_FALSE; } @@ -2127,7 +2127,7 @@ static jboolean android_location_GnssLocationProvider_start(JNIEnv* /* env */, j return checkHidlReturn(result, "IGnss start() failed."); } -static jboolean android_location_GnssLocationProvider_stop(JNIEnv* /* env */, jobject /* obj */) { +static jboolean android_location_gnss_hal_GnssNative_stop(JNIEnv* /* env */, jclass) { if (gnssHal == nullptr) { return JNI_FALSE; } @@ -2136,8 +2136,7 @@ static jboolean android_location_GnssLocationProvider_stop(JNIEnv* /* env */, jo return checkHidlReturn(result, "IGnss stop() failed."); } -static void android_location_GnssLocationProvider_delete_aiding_data(JNIEnv* /* env */, - jobject /* obj */, +static void android_location_gnss_hal_GnssNative_delete_aiding_data(JNIEnv* /* env */, jclass, jint flags) { if (gnssHal == nullptr) { return; @@ -2147,8 +2146,8 @@ static void android_location_GnssLocationProvider_delete_aiding_data(JNIEnv* /* checkHidlReturn(result, "IGnss deleteAidingData() failed."); } -static void android_location_GnssLocationProvider_agps_set_reference_location_cellid( - JNIEnv* /* env */, jobject /* obj */, jint type, jint mcc, jint mnc, jint lac, jint cid) { +static void android_location_gnss_hal_GnssNative_agps_set_reference_location_cellid( + JNIEnv* /* env */, jclass, jint type, jint mcc, jint mnc, jint lac, jint cid) { IAGnssRil_V1_0::AGnssRefLocation location; if (agnssRilIface == nullptr) { @@ -2175,8 +2174,8 @@ static void android_location_GnssLocationProvider_agps_set_reference_location_ce checkHidlReturn(result, "IAGnssRil setRefLocation() failed."); } -static void android_location_GnssLocationProvider_agps_set_id(JNIEnv* env, jobject /* obj */, - jint type, jstring setid_string) { +static void android_location_gnss_hal_GnssNative_agps_set_id(JNIEnv* env, jclass, jint type, + jstring setid_string) { if (agnssRilIface == nullptr) { ALOGE("%s: IAGnssRil interface not available.", __func__); return; @@ -2187,8 +2186,8 @@ static void android_location_GnssLocationProvider_agps_set_id(JNIEnv* env, jobje checkHidlReturn(result, "IAGnssRil setSetId() failed."); } -static jint android_location_GnssLocationProvider_read_nmea(JNIEnv* env, jobject /* obj */, - jbyteArray nmeaArray, jint buffer_size) { +static jint android_location_gnss_hal_GnssNative_read_nmea(JNIEnv* env, jclass, + jbyteArray nmeaArray, jint buffer_size) { // this should only be called from within a call to reportNmea jbyte* nmea = reinterpret_cast(env->GetPrimitiveArrayCritical(nmeaArray, 0)); int length = GnssCallback::sNmeaStringLength; @@ -2199,8 +2198,9 @@ static jint android_location_GnssLocationProvider_read_nmea(JNIEnv* env, jobject return (jint) length; } -static void android_location_GnssLocationProvider_inject_time(JNIEnv* /* env */, jobject /* obj */, - jlong time, jlong timeReference, jint uncertainty) { +static void android_location_gnss_hal_GnssNative_inject_time(JNIEnv* /* env */, jclass, jlong time, + jlong timeReference, + jint uncertainty) { if (gnssHal == nullptr) { return; } @@ -2209,22 +2209,12 @@ static void android_location_GnssLocationProvider_inject_time(JNIEnv* /* env */, checkHidlReturn(result, "IGnss injectTime() failed."); } -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, - jint elapsedRealtimeFlags, - jlong elapsedRealtimeNanos, +static void android_location_gnss_hal_GnssNative_inject_best_location( + JNIEnv* /* env */, jclass, jint gnssLocationFlags, jdouble latitudeDegrees, + jdouble longitudeDegrees, jdouble altitudeMeters, jfloat speedMetersPerSec, + jfloat bearingDegrees, jfloat horizontalAccuracyMeters, jfloat verticalAccuracyMeters, + jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees, jlong timestamp, + jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos, jdouble elapsedRealtimeUncertaintyNanos) { if (gnssHal_V2_0 != nullptr) { GnssLocation_V2_0 location = createGnssLocation_V2_0( @@ -2267,8 +2257,10 @@ static void android_location_GnssLocationProvider_inject_best_location( ALOGE("IGnss injectBestLocation() is called but gnssHal_V1_1 is not available."); } -static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env */, - jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy) { +static void android_location_gnss_hal_GnssNative_inject_location(JNIEnv* /* env */, jclass, + jdouble latitude, + jdouble longitude, + jfloat accuracy) { if (gnssHal == nullptr) { return; } @@ -2277,16 +2269,15 @@ static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env checkHidlReturn(result, "IGnss injectLocation() failed."); } -static jboolean android_location_GnssLocationProvider_supports_psds( - JNIEnv* /* env */, jobject /* obj */) { +static jboolean android_location_gnss_hal_GnssNative_supports_psds(JNIEnv* /* env */, jclass) { return (gnssPsdsAidlIface != nullptr || gnssPsdsIface != nullptr || gnssXtraIface != nullptr) ? JNI_TRUE : JNI_FALSE; } -static void android_location_GnssLocationProvider_inject_psds_data(JNIEnv* env, jobject /* obj */, - jbyteArray data, jint length, - jint psdsType) { +static void android_location_gnss_hal_GnssNative_inject_psds_data(JNIEnv* env, jclass, + jbyteArray data, jint length, + jint psdsType) { if (gnssPsdsAidlIface == nullptr && gnssPsdsIface == nullptr && gnssXtraIface == nullptr) { ALOGE("%s: IGnssPsds or IGnssXtra interface not available.", __func__); return; @@ -2406,8 +2397,8 @@ static void android_location_GnssNetworkConnectivityHandler_agps_data_conn_faile } } -static void android_location_GnssLocationProvider_set_agps_server(JNIEnv* env, jobject /* obj */, - jint type, jstring hostname, jint port) { +static void android_location_gnss_hal_GnssNative_set_agps_server(JNIEnv* env, jclass, jint type, + jstring hostname, jint port) { if (agnssIface_V2_0 != nullptr) { AGnssDispatcher::setServer(agnssIface_V2_0, env, type, hostname, port); @@ -2420,8 +2411,8 @@ static void android_location_GnssLocationProvider_set_agps_server(JNIEnv* env, j } } -static void android_location_GnssLocationProvider_send_ni_response(JNIEnv* /* env */, - jobject /* obj */, jint notifId, jint response) { +static void android_location_gnss_hal_GnssNative_send_ni_response(JNIEnv* /* env */, jclass, + jint notifId, jint response) { if (gnssNiIface == nullptr) { ALOGE("%s: IGnssNi interface not available.", __func__); return; @@ -2504,8 +2495,7 @@ static jstring parseDebugData(JNIEnv* env, std::stringstream& internalState, con return (jstring) env->NewStringUTF(internalState.str().c_str()); } -static jstring android_location_GnssLocationProvider_get_internal_state(JNIEnv* env, - jobject /* obj */) { +static jstring android_location_gnss_hal_GnssNative_get_internal_state(JNIEnv* env, jclass) { jstring internalStateStr = nullptr; /* * TODO: Create a jobject to represent GnssDebug. @@ -2537,8 +2527,7 @@ static jstring android_location_GnssLocationProvider_get_internal_state(JNIEnv* return internalStateStr; } -static void android_location_GnssLocationProvider_request_power_stats(JNIEnv* env, - jobject /* obj */) { +static void android_location_gnss_hal_GnssNative_request_power_stats(JNIEnv* env) { if (gnssPowerIndicationIface == nullptr) { return; } @@ -2546,8 +2535,8 @@ static void android_location_GnssLocationProvider_request_power_stats(JNIEnv* en checkAidlStatus(status, "IGnssPowerIndication requestGnssPowerStats() failed."); } -static jboolean android_location_GnssLocationProvider_is_gnss_visibility_control_supported( - JNIEnv* /* env */, jclass /* clazz */) { +static jboolean android_location_gnss_hal_GnssNative_is_gnss_visibility_control_supported( + JNIEnv* /* env */, jclass) { return (gnssVisibilityControlIface != nullptr) ? JNI_TRUE : JNI_FALSE; } @@ -2587,15 +2576,15 @@ static void android_location_GnssNetworkConnectivityHandler_update_network_state } } -static jboolean android_location_GnssGeofenceProvider_is_geofence_supported( - JNIEnv* /* env */, jobject /* obj */) { +static jboolean android_location_gnss_hal_GnssNative_is_geofence_supported(JNIEnv* /* env */, + jclass) { return (gnssGeofencingIface != nullptr) ? JNI_TRUE : JNI_FALSE; } -static jboolean android_location_GnssGeofenceProvider_add_geofence(JNIEnv* /* env */, - jobject /* obj */, jint geofenceId, jdouble latitude, jdouble longitude, jdouble radius, - jint last_transition, jint monitor_transition, jint notification_responsiveness, - jint unknown_timer) { +static jboolean android_location_gnss_hal_GnssNative_add_geofence( + JNIEnv* /* env */, jclass, jint geofenceId, jdouble latitude, jdouble longitude, + jdouble radius, jint last_transition, jint monitor_transition, + jint notification_responsiveness, jint unknown_timer) { if (gnssGeofencingIface == nullptr) { ALOGE("%s: IGnssGeofencing interface not available.", __func__); return JNI_FALSE; @@ -2608,8 +2597,8 @@ static jboolean android_location_GnssGeofenceProvider_add_geofence(JNIEnv* /* en return checkHidlReturn(result, "IGnssGeofencing addGeofence() failed."); } -static jboolean android_location_GnssGeofenceProvider_remove_geofence(JNIEnv* /* env */, - jobject /* obj */, jint geofenceId) { +static jboolean android_location_gnss_hal_GnssNative_remove_geofence(JNIEnv* /* env */, jclass, + jint geofenceId) { if (gnssGeofencingIface == nullptr) { ALOGE("%s: IGnssGeofencing interface not available.", __func__); return JNI_FALSE; @@ -2619,8 +2608,8 @@ static jboolean android_location_GnssGeofenceProvider_remove_geofence(JNIEnv* /* return checkHidlReturn(result, "IGnssGeofencing removeGeofence() failed."); } -static jboolean android_location_GnssGeofenceProvider_pause_geofence(JNIEnv* /* env */, - jobject /* obj */, jint geofenceId) { +static jboolean android_location_gnss_hal_GnssNative_pause_geofence(JNIEnv* /* env */, jclass, + jint geofenceId) { if (gnssGeofencingIface == nullptr) { ALOGE("%s: IGnssGeofencing interface not available.", __func__); return JNI_FALSE; @@ -2630,8 +2619,9 @@ static jboolean android_location_GnssGeofenceProvider_pause_geofence(JNIEnv* /* return checkHidlReturn(result, "IGnssGeofencing pauseGeofence() failed."); } -static jboolean android_location_GnssGeofenceProvider_resume_geofence(JNIEnv* /* env */, - jobject /* obj */, jint geofenceId, jint monitor_transition) { +static jboolean android_location_gnss_hal_GnssNative_resume_geofence(JNIEnv* /* env */, jclass, + jint geofenceId, + jint monitor_transition) { if (gnssGeofencingIface == nullptr) { ALOGE("%s: IGnssGeofencing interface not available.", __func__); return JNI_FALSE; @@ -2641,16 +2631,16 @@ static jboolean android_location_GnssGeofenceProvider_resume_geofence(JNIEnv* /* return checkHidlReturn(result, "IGnssGeofencing resumeGeofence() failed."); } -static jboolean android_location_GnssAntennaInfoProvider_is_antenna_info_supported(JNIEnv* env, - jclass clazz) { +static jboolean android_location_gnss_hal_GnssNative_is_antenna_info_supported(JNIEnv* env, + jclass) { if (gnssAntennaInfoIface != nullptr) { return JNI_TRUE; } return JNI_FALSE; } -static jboolean android_location_GnssAntennaInfoProvider_start_antenna_info_listening( - JNIEnv* /* env */, jobject /* obj */) { +static jboolean android_location_gnss_hal_GnssNative_start_antenna_info_listening(JNIEnv* /* env */, + jclass) { if (gnssAntennaInfoIface == nullptr) { ALOGE("%s: IGnssAntennaInfo interface not available.", __func__); return JNI_FALSE; @@ -2676,8 +2666,8 @@ static jboolean android_location_GnssAntennaInfoProvider_start_antenna_info_list return JNI_TRUE; } -static jboolean android_location_GnssAntennaInfoProvider_stop_antenna_info_listening( - JNIEnv* /* env */, jobject /* obj */) { +static jboolean android_location_gnss_hal_GnssNative_stop_antenna_info_listening(JNIEnv* /* env */, + jclass) { if (gnssAntennaInfoIface == nullptr) { ALOGE("%s: IGnssAntennaInfo interface not available.", __func__); return JNI_FALSE; @@ -2687,8 +2677,7 @@ static jboolean android_location_GnssAntennaInfoProvider_stop_antenna_info_liste return checkHidlReturn(result, "IGnssAntennaInfo close() failed."); } -static jboolean android_location_GnssMeasurementsProvider_is_measurement_supported( - JNIEnv* env, jclass clazz) { +static jboolean android_location_gnss_hal_GnssNative_is_measurement_supported(JNIEnv* env, jclass) { if (gnssMeasurementIface != nullptr) { return JNI_TRUE; } @@ -2696,10 +2685,8 @@ static jboolean android_location_GnssMeasurementsProvider_is_measurement_support return JNI_FALSE; } -static jboolean android_location_GnssMeasurementsProvider_start_measurement_collection( - JNIEnv* /* env */, - jobject /* obj */, - jboolean enableFullTracking) { +static jboolean android_location_gnss_hal_GnssNative_start_measurement_collection( + JNIEnv* /* env */, jclass, jboolean enableFullTracking) { if (gnssMeasurementIface == nullptr) { ALOGE("%s: IGnssMeasurement interface not available.", __func__); return JNI_FALSE; @@ -2710,9 +2697,8 @@ static jboolean android_location_GnssMeasurementsProvider_start_measurement_coll enableFullTracking); } -static jboolean android_location_GnssMeasurementsProvider_stop_measurement_collection( - JNIEnv* env, - jobject obj) { +static jboolean android_location_gnss_hal_GnssNative_stop_measurement_collection(JNIEnv* env, + jclass) { if (gnssMeasurementIface == nullptr) { ALOGE("%s: IGnssMeasurement interface not available.", __func__); return JNI_FALSE; @@ -2721,9 +2707,8 @@ static jboolean android_location_GnssMeasurementsProvider_stop_measurement_colle return gnssMeasurementIface->close(); } -static jboolean - android_location_GnssMeasurementCorrectionsProvider_is_measurement_corrections_supported( - JNIEnv* env, jclass clazz) { +static jboolean android_location_gnss_hal_GnssNative_is_measurement_corrections_supported( + JNIEnv* env, jclass) { if (gnssCorrectionsIface_V1_0 != nullptr || gnssCorrectionsIface_V1_1 != nullptr) { return JNI_TRUE; } @@ -2816,12 +2801,9 @@ static void getSingleSatCorrectionList_1_0(JNIEnv* env, jobject singleSatCorrect list[i] = singleSatCorrection; } } -static jboolean - android_location_GnssMeasurementCorrectionsProvider_inject_gnss_measurement_corrections( - JNIEnv* env, - jobject obj /* clazz*/, - jobject correctionsObj) { +static jboolean android_location_gnss_hal_GnssNative_inject_measurement_corrections( + JNIEnv* env, jclass, jobject correctionsObj) { if (gnssCorrectionsIface_V1_0 == nullptr && gnssCorrectionsIface_V1_1 == nullptr) { ALOGW("Trying to inject GNSS measurement corrections on a chipset that does not" " support them."); @@ -2893,18 +2875,16 @@ static jboolean return checkHidlReturn(result, "IMeasurementCorrections 1.0 setCorrections() failed."); } -static jboolean android_location_GnssNavigationMessageProvider_is_navigation_message_supported( - JNIEnv* env, - jclass clazz) { +static jboolean android_location_gnss_hal_GnssNative_is_navigation_message_supported(JNIEnv* env, + jclass) { if (gnssNavigationMessageIface != nullptr) { return JNI_TRUE; } return JNI_FALSE; } -static jboolean android_location_GnssNavigationMessageProvider_start_navigation_message_collection( - JNIEnv* env, - jobject obj) { +static jboolean android_location_gnss_hal_GnssNative_start_navigation_message_collection( + JNIEnv* env, jclass) { if (gnssNavigationMessageIface == nullptr) { ALOGE("%s: IGnssNavigationMessage interface not available.", __func__); return JNI_FALSE; @@ -2926,9 +2906,8 @@ static jboolean android_location_GnssNavigationMessageProvider_start_navigation_ return JNI_TRUE; } -static jboolean android_location_GnssNavigationMessageProvider_stop_navigation_message_collection( - JNIEnv* env, - jobject obj) { +static jboolean android_location_gnss_hal_GnssNative_stop_navigation_message_collection(JNIEnv* env, + jclass) { if (gnssNavigationMessageIface == nullptr) { ALOGE("%s: IGnssNavigationMessage interface not available.", __func__); return JNI_FALSE; @@ -3027,7 +3006,7 @@ static jboolean android_location_GnssConfiguration_set_es_extension_sec( return gnssConfigurationIface->setEsExtensionSec(emergencyExtensionSeconds); } -static jint android_location_GnssLocationProvider_get_batch_size(JNIEnv*, jclass) { +static jint android_location_gnss_hal_GnssNative_get_batch_size(JNIEnv*) { if (gnssBatchingIface == nullptr) { return 0; // batching not supported, size = 0 } @@ -3039,7 +3018,7 @@ static jint android_location_GnssLocationProvider_get_batch_size(JNIEnv*, jclass return static_cast(result); } -static jboolean android_location_GnssLocationProvider_init_batching(JNIEnv*, jclass) { +static jboolean android_location_gnss_hal_GnssNative_init_batching(JNIEnv*, jclass) { if (gnssBatchingIface_V2_0 != nullptr) { sp gnssBatchingCbIface_V2_0 = new GnssBatchingCallback_V2_0(); auto result = gnssBatchingIface_V2_0->init_2_0(gnssBatchingCbIface_V2_0); @@ -3053,7 +3032,7 @@ static jboolean android_location_GnssLocationProvider_init_batching(JNIEnv*, jcl } } -static void android_location_GnssLocationProvider_cleanup_batching(JNIEnv*, jclass) { +static void android_location_gnss_hal_GnssNative_cleanup_batching(JNIEnv*, jclass) { if (gnssBatchingIface == nullptr) { return; // batching not supported } @@ -3061,9 +3040,8 @@ static void android_location_GnssLocationProvider_cleanup_batching(JNIEnv*, jcla checkHidlReturn(result, "IGnssBatching cleanup() failed."); } -static jboolean android_location_GnssLocationProvider_start_batch(JNIEnv*, jclass, - jlong periodNanos, - jboolean wakeOnFifoFull) { +static jboolean android_location_gnss_hal_GnssNative_start_batch(JNIEnv*, jclass, jlong periodNanos, + jboolean wakeOnFifoFull) { if (gnssBatchingIface == nullptr) { return JNI_FALSE; // batching not supported } @@ -3080,7 +3058,7 @@ static jboolean android_location_GnssLocationProvider_start_batch(JNIEnv*, jclas return checkHidlReturn(result, "IGnssBatching start() failed."); } -static void android_location_GnssLocationProvider_flush_batch(JNIEnv*, jclass) { +static void android_location_gnss_hal_GnssNative_flush_batch(JNIEnv*, jclass) { if (gnssBatchingIface == nullptr) { return; // batching not supported } @@ -3088,7 +3066,7 @@ static void android_location_GnssLocationProvider_flush_batch(JNIEnv*, jclass) { checkHidlReturn(result, "IGnssBatching flush() failed."); } -static jboolean android_location_GnssLocationProvider_stop_batch(JNIEnv*, jclass) { +static jboolean android_location_gnss_hal_GnssNative_stop_batch(JNIEnv*, jclass) { if (gnssBatchingIface == nullptr) { return JNI_FALSE; // batching not supported } @@ -3118,156 +3096,146 @@ static jboolean android_location_GnssVisibilityControl_enable_nfw_location_acces static const JNINativeMethod sCoreMethods[] = { /* name, signature, funcPtr */ {"native_class_init_once", "()V", - reinterpret_cast(android_location_GnssNative_class_init_once)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_class_init_once)}, {"native_is_supported", "()Z", - reinterpret_cast(android_location_GnssNative_is_supported)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_is_supported)}, {"native_init_once", "(Z)V", - reinterpret_cast(android_location_GnssNative_init_once)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_init_once)}, }; static const JNINativeMethod sLocationProviderMethods[] = { /* name, signature, funcPtr */ - {"native_init", "()Z", reinterpret_cast(android_location_GnssLocationProvider_init)}, + {"native_init", "()Z", reinterpret_cast(android_location_gnss_hal_GnssNative_init)}, {"native_cleanup", "()V", - reinterpret_cast(android_location_GnssLocationProvider_cleanup)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_cleanup)}, {"native_set_position_mode", "(IIIIIZ)Z", - reinterpret_cast(android_location_GnssLocationProvider_set_position_mode)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_set_position_mode)}, {"native_start", "()Z", - reinterpret_cast(android_location_GnssLocationProvider_start)}, - {"native_stop", "()Z", reinterpret_cast(android_location_GnssLocationProvider_stop)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_start)}, + {"native_stop", "()Z", reinterpret_cast(android_location_gnss_hal_GnssNative_stop)}, {"native_delete_aiding_data", "(I)V", - reinterpret_cast(android_location_GnssLocationProvider_delete_aiding_data)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_delete_aiding_data)}, {"native_read_nmea", "([BI)I", - reinterpret_cast(android_location_GnssLocationProvider_read_nmea)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_read_nmea)}, {"native_inject_time", "(JJI)V", - reinterpret_cast(android_location_GnssLocationProvider_inject_time)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_inject_time)}, {"native_inject_best_location", "(IDDDFFFFFFJIJD)V", - reinterpret_cast(android_location_GnssLocationProvider_inject_best_location)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_inject_best_location)}, {"native_inject_location", "(DDF)V", - reinterpret_cast(android_location_GnssLocationProvider_inject_location)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_inject_location)}, {"native_supports_psds", "()Z", - reinterpret_cast(android_location_GnssLocationProvider_supports_psds)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_supports_psds)}, {"native_inject_psds_data", "([BII)V", - reinterpret_cast(android_location_GnssLocationProvider_inject_psds_data)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_inject_psds_data)}, {"native_agps_set_id", "(ILjava/lang/String;)V", - reinterpret_cast(android_location_GnssLocationProvider_agps_set_id)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_agps_set_id)}, {"native_agps_set_ref_location_cellid", "(IIIII)V", reinterpret_cast( - android_location_GnssLocationProvider_agps_set_reference_location_cellid)}, + android_location_gnss_hal_GnssNative_agps_set_reference_location_cellid)}, {"native_set_agps_server", "(ILjava/lang/String;I)V", - reinterpret_cast(android_location_GnssLocationProvider_set_agps_server)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_set_agps_server)}, {"native_send_ni_response", "(II)V", - reinterpret_cast(android_location_GnssLocationProvider_send_ni_response)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_send_ni_response)}, {"native_get_internal_state", "()Ljava/lang/String;", - reinterpret_cast(android_location_GnssLocationProvider_get_internal_state)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_get_internal_state)}, {"native_is_gnss_visibility_control_supported", "()Z", reinterpret_cast( - android_location_GnssLocationProvider_is_gnss_visibility_control_supported)}, + android_location_gnss_hal_GnssNative_is_gnss_visibility_control_supported)}, }; -static const JNINativeMethod sMethodsBatching[] = { +static const JNINativeMethod sBatchingMethods[] = { /* name, signature, funcPtr */ {"native_get_batch_size", "()I", - reinterpret_cast(android_location_GnssLocationProvider_get_batch_size)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_get_batch_size)}, {"native_start_batch", "(JZ)Z", - reinterpret_cast(android_location_GnssLocationProvider_start_batch)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_start_batch)}, {"native_flush_batch", "()V", - reinterpret_cast(android_location_GnssLocationProvider_flush_batch)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_flush_batch)}, {"native_stop_batch", "()Z", - reinterpret_cast(android_location_GnssLocationProvider_stop_batch)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_stop_batch)}, {"native_init_batching", "()Z", - reinterpret_cast(android_location_GnssLocationProvider_init_batching)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_init_batching)}, {"native_cleanup_batching", "()V", - reinterpret_cast(android_location_GnssLocationProvider_cleanup_batching)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_cleanup_batching)}, }; static const JNINativeMethod sAntennaInfoMethods[] = { /* name, signature, funcPtr */ {"native_is_antenna_info_supported", "()Z", - reinterpret_cast( - android_location_GnssAntennaInfoProvider_is_antenna_info_supported)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_is_antenna_info_supported)}, {"native_start_antenna_info_listening", "()Z", reinterpret_cast( - android_location_GnssAntennaInfoProvider_start_antenna_info_listening)}, + android_location_gnss_hal_GnssNative_start_antenna_info_listening)}, {"native_stop_antenna_info_listening", "()Z", - reinterpret_cast( - android_location_GnssAntennaInfoProvider_stop_antenna_info_listening)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_stop_antenna_info_listening)}, }; static const JNINativeMethod sGeofenceMethods[] = { - /* name, signature, funcPtr */ - {"native_is_geofence_supported", - "()Z", - reinterpret_cast(android_location_GnssGeofenceProvider_is_geofence_supported)}, - {"native_add_geofence", - "(IDDDIIII)Z", - reinterpret_cast(android_location_GnssGeofenceProvider_add_geofence)}, - {"native_remove_geofence", - "(I)Z", - reinterpret_cast(android_location_GnssGeofenceProvider_remove_geofence)}, - {"native_pause_geofence", "(I)Z", reinterpret_cast( - android_location_GnssGeofenceProvider_pause_geofence)}, - {"native_resume_geofence", - "(II)Z", - reinterpret_cast(android_location_GnssGeofenceProvider_resume_geofence)}, + /* name, signature, funcPtr */ + {"native_is_geofence_supported", "()Z", + reinterpret_cast(android_location_gnss_hal_GnssNative_is_geofence_supported)}, + {"native_add_geofence", "(IDDDIIII)Z", + reinterpret_cast(android_location_gnss_hal_GnssNative_add_geofence)}, + {"native_remove_geofence", "(I)Z", + reinterpret_cast(android_location_gnss_hal_GnssNative_remove_geofence)}, + {"native_pause_geofence", "(I)Z", + reinterpret_cast(android_location_gnss_hal_GnssNative_pause_geofence)}, + {"native_resume_geofence", "(II)Z", + reinterpret_cast(android_location_gnss_hal_GnssNative_resume_geofence)}, }; static const JNINativeMethod sMeasurementMethods[] = { - /* name, signature, funcPtr */ - {"native_is_measurement_supported", "()Z", - reinterpret_cast( - android_location_GnssMeasurementsProvider_is_measurement_supported)}, - {"native_start_measurement_collection", "(Z)Z", - reinterpret_cast( - android_location_GnssMeasurementsProvider_start_measurement_collection)}, - {"native_stop_measurement_collection", "()Z", - reinterpret_cast( - android_location_GnssMeasurementsProvider_stop_measurement_collection)}, + /* name, signature, funcPtr */ + {"native_is_measurement_supported", "()Z", + reinterpret_cast(android_location_gnss_hal_GnssNative_is_measurement_supported)}, + {"native_start_measurement_collection", "(Z)Z", + reinterpret_cast( + android_location_gnss_hal_GnssNative_start_measurement_collection)}, + {"native_stop_measurement_collection", "()Z", + reinterpret_cast(android_location_gnss_hal_GnssNative_stop_measurement_collection)}, }; static const JNINativeMethod sMeasurementCorrectionsMethods[] = { - /* name, signature, funcPtr */ - {"native_is_measurement_corrections_supported", "()Z", - reinterpret_cast( - android_location_GnssMeasurementCorrectionsProvider_is_measurement_corrections_supported)}, - {"native_inject_gnss_measurement_corrections", - "(Landroid/location/GnssMeasurementCorrections;)Z", - reinterpret_cast( - android_location_GnssMeasurementCorrectionsProvider_inject_gnss_measurement_corrections)}, + /* name, signature, funcPtr */ + {"native_is_measurement_corrections_supported", "()Z", + reinterpret_cast( + android_location_gnss_hal_GnssNative_is_measurement_corrections_supported)}, + {"native_inject_measurement_corrections", + "(Landroid/location/GnssMeasurementCorrections;)Z", + reinterpret_cast( + android_location_gnss_hal_GnssNative_inject_measurement_corrections)}, }; static const JNINativeMethod sNavigationMessageMethods[] = { - /* name, signature, funcPtr */ - {"native_is_navigation_message_supported", - "()Z", - reinterpret_cast( - android_location_GnssNavigationMessageProvider_is_navigation_message_supported)}, - {"native_start_navigation_message_collection", - "()Z", - reinterpret_cast( - android_location_GnssNavigationMessageProvider_start_navigation_message_collection)}, - {"native_stop_navigation_message_collection", - "()Z", - reinterpret_cast( - android_location_GnssNavigationMessageProvider_stop_navigation_message_collection)}, + /* name, signature, funcPtr */ + {"native_is_navigation_message_supported", "()Z", + reinterpret_cast( + android_location_gnss_hal_GnssNative_is_navigation_message_supported)}, + {"native_start_navigation_message_collection", "()Z", + reinterpret_cast( + android_location_gnss_hal_GnssNative_start_navigation_message_collection)}, + {"native_stop_navigation_message_collection", "()Z", + reinterpret_cast( + android_location_gnss_hal_GnssNative_stop_navigation_message_collection)}, }; static const JNINativeMethod sNetworkConnectivityMethods[] = { - /* name, signature, funcPtr */ - {"native_is_agps_ril_supported", "()Z", - reinterpret_cast(android_location_GnssNetworkConnectivityHandler_is_agps_ril_supported)}, - {"native_update_network_state", - "(ZIZZLjava/lang/String;JS)V", - reinterpret_cast(android_location_GnssNetworkConnectivityHandler_update_network_state)}, - {"native_agps_data_conn_open", - "(JLjava/lang/String;I)V", - reinterpret_cast(android_location_GnssNetworkConnectivityHandler_agps_data_conn_open)}, - {"native_agps_data_conn_closed", - "()V", - reinterpret_cast(android_location_GnssNetworkConnectivityHandler_agps_data_conn_closed)}, - {"native_agps_data_conn_failed", - "()V", - reinterpret_cast(android_location_GnssNetworkConnectivityHandler_agps_data_conn_failed)}, + /* name, signature, funcPtr */ + {"native_is_agps_ril_supported", "()Z", + reinterpret_cast( + android_location_GnssNetworkConnectivityHandler_is_agps_ril_supported)}, + {"native_update_network_state", "(ZIZZLjava/lang/String;JS)V", + reinterpret_cast( + android_location_GnssNetworkConnectivityHandler_update_network_state)}, + {"native_agps_data_conn_open", "(JLjava/lang/String;I)V", + reinterpret_cast( + android_location_GnssNetworkConnectivityHandler_agps_data_conn_open)}, + {"native_agps_data_conn_closed", "()V", + reinterpret_cast( + android_location_GnssNetworkConnectivityHandler_agps_data_conn_closed)}, + {"native_agps_data_conn_failed", "()V", + reinterpret_cast( + android_location_GnssNetworkConnectivityHandler_agps_data_conn_failed)}, }; static const JNINativeMethod sConfigurationMethods[] = { @@ -3297,45 +3265,73 @@ static const JNINativeMethod sConfigurationMethods[] = { }; static const JNINativeMethod sVisibilityControlMethods[] = { - /* name, signature, funcPtr */ - {"native_enable_nfw_location_access", - "([Ljava/lang/String;)Z", - reinterpret_cast( - android_location_GnssVisibilityControl_enable_nfw_location_access)}, + /* name, signature, funcPtr */ + {"native_enable_nfw_location_access", "([Ljava/lang/String;)Z", + reinterpret_cast( + android_location_GnssVisibilityControl_enable_nfw_location_access)}, }; static const JNINativeMethod sPowerIndicationMethods[] = { /* name, signature, funcPtr */ {"native_request_power_stats", "()V", - reinterpret_cast(android_location_GnssLocationProvider_request_power_stats)}, + reinterpret_cast(android_location_gnss_hal_GnssNative_request_power_stats)}, }; int register_android_server_location_GnssLocationProvider(JNIEnv* env) { - jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssAntennaInfoProvider", - sAntennaInfoMethods, NELEM(sAntennaInfoMethods)); - jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssLocationProvider", - sMethodsBatching, NELEM(sMethodsBatching)); - jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssGeofenceProvider", - sGeofenceMethods, NELEM(sGeofenceMethods)); - jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssMeasurementsProvider", - sMeasurementMethods, NELEM(sMeasurementMethods)); - jniRegisterNativeMethods(env, - "com/android/server/location/gnss/GnssMeasurementCorrectionsProvider", - sMeasurementCorrectionsMethods, NELEM(sMeasurementCorrectionsMethods)); - jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssNavigationMessageProvider", - sNavigationMessageMethods, NELEM(sNavigationMessageMethods)); - jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssNetworkConnectivityHandler", - sNetworkConnectivityMethods, NELEM(sNetworkConnectivityMethods)); - jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssConfiguration", - sConfigurationMethods, NELEM(sConfigurationMethods)); - jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssVisibilityControl", - sVisibilityControlMethods, NELEM(sVisibilityControlMethods)); - jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssPowerIndicationProvider", - sPowerIndicationMethods, NELEM(sPowerIndicationMethods)); - jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssLocationProvider", - sLocationProviderMethods, NELEM(sLocationProviderMethods)); - return jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssNative", - sCoreMethods, NELEM(sCoreMethods)); + int res; + + res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative", + sAntennaInfoMethods, NELEM(sAntennaInfoMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative", + sBatchingMethods, NELEM(sBatchingMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative", + sGeofenceMethods, NELEM(sGeofenceMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative", + sMeasurementMethods, NELEM(sMeasurementMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative", + sMeasurementCorrectionsMethods, + NELEM(sMeasurementCorrectionsMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative", + sNavigationMessageMethods, NELEM(sNavigationMessageMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + res = jniRegisterNativeMethods(env, + "com/android/server/location/gnss/" + "GnssNetworkConnectivityHandler", + sNetworkConnectivityMethods, NELEM(sNetworkConnectivityMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssConfiguration", + sConfigurationMethods, NELEM(sConfigurationMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssVisibilityControl", + sVisibilityControlMethods, NELEM(sVisibilityControlMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative", + sPowerIndicationMethods, NELEM(sPowerIndicationMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative", + sLocationProviderMethods, NELEM(sLocationProviderMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative", + sCoreMethods, NELEM(sCoreMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + return 0; } } /* namespace android */ diff --git a/services/robotests/src/com/android/server/location/gnss/GnssGeofenceProviderTest.java b/services/robotests/src/com/android/server/location/gnss/GnssGeofenceProviderTest.java deleted file mode 100644 index 48e6ce8cf350d..0000000000000 --- a/services/robotests/src/com/android/server/location/gnss/GnssGeofenceProviderTest.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.location.gnss; - -import static org.mockito.ArgumentMatchers.anyDouble; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.os.RemoteException; -import android.platform.test.annotations.Presubmit; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; - -/** - * Unit tests for {@link GnssGeofenceProvider}. - */ -@RunWith(RobolectricTestRunner.class) -@Presubmit -public class GnssGeofenceProviderTest { - private static final int GEOFENCE_ID = 12345; - private static final double LATITUDE = 10.0; - private static final double LONGITUDE = 20.0; - private static final double RADIUS = 5.0; - private static final int LAST_TRANSITION = 0; - private static final int MONITOR_TRANSITIONS = 0; - private static final int NOTIFICATION_RESPONSIVENESS = 0; - private static final int UNKNOWN_TIMER = 0; - @Mock - private GnssGeofenceProvider.GnssGeofenceProviderNative mMockNative; - private GnssGeofenceProvider mTestProvider; - - /** - * Mocks native methods and adds a geofence to the GnssGeofenceProvider. - */ - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - when(mMockNative.addGeofence(anyInt(), anyDouble(), anyDouble(), anyDouble(), anyInt(), - anyInt(), anyInt(), anyInt())).thenReturn(true); - when(mMockNative.pauseGeofence(anyInt())).thenReturn(true); - when(mMockNative.removeGeofence(anyInt())).thenReturn(true); - when(mMockNative.resumeGeofence(anyInt(), anyInt())).thenReturn(true); - mTestProvider = new GnssGeofenceProvider(mMockNative); - mTestProvider.addCircularHardwareGeofence(GEOFENCE_ID, LATITUDE, - LONGITUDE, RADIUS, LAST_TRANSITION, MONITOR_TRANSITIONS, - NOTIFICATION_RESPONSIVENESS, - UNKNOWN_TIMER); - } - - /** - * Verify native add geofence method is called. - */ - @Test - public void addGeofence_nativeAdded() { - verify(mMockNative).addGeofence(eq(GEOFENCE_ID), eq(LATITUDE), eq(LONGITUDE), - eq(RADIUS), eq(LAST_TRANSITION), eq(MONITOR_TRANSITIONS), - eq(NOTIFICATION_RESPONSIVENESS), - eq(UNKNOWN_TIMER)); - } - - /** - * Verify pauseHardwareGeofence calls native pauseGeofence method. - */ - @Test - public void pauseGeofence_nativePaused() { - mTestProvider.pauseHardwareGeofence(GEOFENCE_ID); - verify(mMockNative).pauseGeofence(eq(GEOFENCE_ID)); - } - - /** - * Verify removeHardwareGeofence calls native removeGeofence method. - */ - @Test - public void removeGeofence_nativeRemoved() { - mTestProvider.removeHardwareGeofence(GEOFENCE_ID); - verify(mMockNative).removeGeofence(eq(GEOFENCE_ID)); - } - - /** - * Verify resumeHardwareGeofence, called after pauseHardwareGeofence, will call native - * resumeGeofence method. - */ - @Test - public void resumeGeofence_nativeResumed() { - mTestProvider.pauseHardwareGeofence(GEOFENCE_ID); - mTestProvider.resumeHardwareGeofence(GEOFENCE_ID, MONITOR_TRANSITIONS); - verify(mMockNative).resumeGeofence(eq(GEOFENCE_ID), eq(MONITOR_TRANSITIONS)); - } - - /** - * Verify resumeIfStarted method will re-add previously added geofences. - */ - @Test - public void addGeofence_restart_added() throws RemoteException { - mTestProvider.resumeIfStarted(); - - verify(mMockNative, times(2)).addGeofence(eq(GEOFENCE_ID), eq(LATITUDE), eq(LONGITUDE), - eq(RADIUS), eq(LAST_TRANSITION), eq(MONITOR_TRANSITIONS), - eq(NOTIFICATION_RESPONSIVENESS), - eq(UNKNOWN_TIMER)); - } - - /** - * Verify resumeIfStarted method will not re-add previously added geofences if they have been - * removed. - */ - @Test - public void removeGeofence_restart_notAdded() throws RemoteException { - mTestProvider.removeHardwareGeofence(GEOFENCE_ID); - mTestProvider.resumeIfStarted(); - - verify(mMockNative, times(1)).addGeofence(eq(GEOFENCE_ID), eq(LATITUDE), eq(LONGITUDE), - eq(RADIUS), eq(LAST_TRANSITION), eq(MONITOR_TRANSITIONS), - eq(NOTIFICATION_RESPONSIVENESS), - eq(UNKNOWN_TIMER)); - } - - /** - * Verify resumeIfStarted, called after pauseHardwareGeofence, will re-add previously added - * geofences, and re-pause geofencing. - */ - @Test - public void pauseGeofence_restart_paused() throws RemoteException { - mTestProvider.pauseHardwareGeofence(GEOFENCE_ID); - mTestProvider.resumeIfStarted(); - - verify(mMockNative, times(2)).addGeofence(eq(GEOFENCE_ID), eq(LATITUDE), eq(LONGITUDE), - eq(RADIUS), eq(LAST_TRANSITION), eq(MONITOR_TRANSITIONS), - eq(NOTIFICATION_RESPONSIVENESS), - eq(UNKNOWN_TIMER)); - verify(mMockNative, times(2)).pauseGeofence(eq(GEOFENCE_ID)); - } -} diff --git a/services/robotests/src/com/android/server/location/gnss/GnssPositionModeTest.java b/services/robotests/src/com/android/server/location/gnss/GnssPositionModeTest.java deleted file mode 100644 index e7d3e513a142b..0000000000000 --- a/services/robotests/src/com/android/server/location/gnss/GnssPositionModeTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.location.gnss; - -import static com.google.common.truth.Truth.assertThat; - -import android.platform.test.annotations.Presubmit; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; - -import java.util.HashSet; - -/** - * Unit tests for {@link GnssPositionMode}. - */ -@RunWith(RobolectricTestRunner.class) -@Presubmit -public class GnssPositionModeTest { - - private GnssPositionMode mPositionMode1 = createGnssPositionMode(0, 1000); - private GnssPositionMode mPositionMode2 = createGnssPositionMode(0, 1000); - private GnssPositionMode mPositionMode3 = createGnssPositionMode(1, 1000); - - /** - * Verifies hashcode method. - */ - @Test - public void testHashCode() { - assertThat(mPositionMode1.hashCode()).isEqualTo(mPositionMode2.hashCode()); - assertThat(mPositionMode1.hashCode()).isNotEqualTo(mPositionMode3.hashCode()); - assertThat(mPositionMode1.hashCode()).isNotEqualTo(mPositionMode3.hashCode()); - - HashSet hashSet = new HashSet<>(); - hashSet.add(mPositionMode1.hashCode()); - hashSet.add(mPositionMode2.hashCode()); - assertThat(hashSet.size()).isEqualTo(1); - hashSet.add(mPositionMode3.hashCode()); - assertThat(hashSet.size()).isEqualTo(2); - } - - /** - * Verify that GnssPositionMode objects that return true for equals() also have the same - * hashcode. - */ - @Test - public void checkIfEqualsImpliesSameHashCode() { - assertTEqualsImpliesSameHashCode(mPositionMode1, mPositionMode2); - assertTEqualsImpliesSameHashCode(mPositionMode2, mPositionMode3); - } - - private void assertTEqualsImpliesSameHashCode(GnssPositionMode mode1, GnssPositionMode mode2) { - if (mode1.equals(mode2)) { - assertThat(mode1.hashCode()).isEqualTo(mode2.hashCode()); - } - } - - private GnssPositionMode createGnssPositionMode(int mode, int minInterval) { - return new GnssPositionMode(mode, 0, minInterval, 0, 0, true); - } -} diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssGeofenceProxyTest.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssGeofenceProxyTest.java new file mode 100644 index 0000000000000..b480f24fb3710 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssGeofenceProxyTest.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.location.gnss; + +import static com.google.common.truth.Truth.assertThat; + +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.server.location.gnss.hal.FakeGnssHal; +import com.android.server.location.gnss.hal.GnssNative; +import com.android.server.location.injector.TestInjector; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Objects; + +@Presubmit +@SmallTest +@RunWith(AndroidJUnit4.class) +public class GnssGeofenceProxyTest { + + private static final int GEOFENCE_ID = 12345; + private static final double LATITUDE = 10.0; + private static final double LONGITUDE = 20.0; + private static final double RADIUS = 5.0; + private static final int LAST_TRANSITION = 0; + private static final int MONITOR_TRANSITIONS = 0; + private static final int NOTIFICATION_RESPONSIVENESS = 0; + private static final int UNKNOWN_TIMER = 0; + + private @Mock GnssConfiguration mMockConfiguration; + private @Mock GnssNative.GeofenceCallbacks mGeofenceCallbacks; + + private FakeGnssHal mFakeHal; + private GnssGeofenceProxy mTestProvider; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mFakeHal = new FakeGnssHal(); + GnssNative.setGnssHalForTest(mFakeHal); + + GnssNative gnssNative = Objects.requireNonNull( + GnssNative.create(new TestInjector(), mMockConfiguration)); + gnssNative.setGeofenceCallbacks(mGeofenceCallbacks); + mTestProvider = new GnssGeofenceProxy(gnssNative); + gnssNative.register(); + + mTestProvider.addCircularHardwareGeofence(GEOFENCE_ID, LATITUDE, LONGITUDE, RADIUS, + LAST_TRANSITION, MONITOR_TRANSITIONS, NOTIFICATION_RESPONSIVENESS, UNKNOWN_TIMER); + } + + @Test + public void testAddGeofence() { + assertThat(mFakeHal.getGeofences()).containsExactly(new FakeGnssHal.GnssHalGeofence( + GEOFENCE_ID, LATITUDE, LONGITUDE, RADIUS, LAST_TRANSITION, MONITOR_TRANSITIONS, + NOTIFICATION_RESPONSIVENESS, UNKNOWN_TIMER, false)); + } + + @Test + public void testRemoveGeofence() { + mTestProvider.removeHardwareGeofence(GEOFENCE_ID); + + assertThat(mFakeHal.getGeofences()).isEmpty(); + } + + @Test + public void testPauseGeofence() { + mTestProvider.pauseHardwareGeofence(GEOFENCE_ID); + + assertThat(mFakeHal.getGeofences()).containsExactly(new FakeGnssHal.GnssHalGeofence( + GEOFENCE_ID, LATITUDE, LONGITUDE, RADIUS, LAST_TRANSITION, MONITOR_TRANSITIONS, + NOTIFICATION_RESPONSIVENESS, UNKNOWN_TIMER, true)); + } + + @Test + public void testResumeGeofence() { + mTestProvider.pauseHardwareGeofence(GEOFENCE_ID); + mTestProvider.resumeHardwareGeofence(GEOFENCE_ID, MONITOR_TRANSITIONS); + + assertThat(mFakeHal.getGeofences()).containsExactly(new FakeGnssHal.GnssHalGeofence( + GEOFENCE_ID, LATITUDE, LONGITUDE, RADIUS, LAST_TRANSITION, MONITOR_TRANSITIONS, + NOTIFICATION_RESPONSIVENESS, UNKNOWN_TIMER, false)); + } + + @Test + public void testAddGeofence_restart() { + mFakeHal.restartHal(); + + assertThat(mFakeHal.getGeofences()).containsExactly(new FakeGnssHal.GnssHalGeofence( + GEOFENCE_ID, LATITUDE, LONGITUDE, RADIUS, LAST_TRANSITION, MONITOR_TRANSITIONS, + NOTIFICATION_RESPONSIVENESS, UNKNOWN_TIMER, false)); + } + + @Test + public void testRemoveGeofence_restart() { + mTestProvider.removeHardwareGeofence(GEOFENCE_ID); + mFakeHal.restartHal(); + + assertThat(mFakeHal.getGeofences()).isEmpty(); + } + + @Test + public void testPauseGeofence_restart() { + mTestProvider.pauseHardwareGeofence(GEOFENCE_ID); + mFakeHal.restartHal(); + + assertThat(mFakeHal.getGeofences()).containsExactly(new FakeGnssHal.GnssHalGeofence( + GEOFENCE_ID, LATITUDE, LONGITUDE, RADIUS, LAST_TRANSITION, MONITOR_TRANSITIONS, + NOTIFICATION_RESPONSIVENESS, UNKNOWN_TIMER, true)); + } +} diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java deleted file mode 100644 index 2b21cc5820879..0000000000000 --- a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java +++ /dev/null @@ -1,682 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.location.gnss; - -import static android.app.AppOpsManager.OP_COARSE_LOCATION; -import static android.app.AppOpsManager.OP_FINE_LOCATION; -import static android.location.LocationManager.GPS_PROVIDER; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.nullable; -import static org.mockito.Mockito.after; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.timeout; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.testng.Assert.assertThrows; - -import android.Manifest; -import android.content.Context; -import android.content.pm.PackageManager; -import android.location.GnssAntennaInfo; -import android.location.GnssAntennaInfo.SphericalCorrections; -import android.location.GnssClock; -import android.location.GnssMeasurementCorrections; -import android.location.GnssMeasurementRequest; -import android.location.GnssMeasurementsEvent; -import android.location.GnssNavigationMessage; -import android.location.GnssSingleSatCorrection; -import android.location.IGnssAntennaInfoListener; -import android.location.IGnssMeasurementsListener; -import android.location.IGnssNavigationMessageListener; -import android.location.IGnssStatusListener; -import android.location.INetInitiatedListener; -import android.location.LocationManagerInternal; -import android.os.Handler; -import android.os.IBinder; -import android.os.IInterface; -import android.os.Message; -import android.os.RemoteException; - -import com.android.server.LocalServices; -import com.android.server.location.gnss.GnssAntennaInfoProvider.GnssAntennaInfoProviderNative; -import com.android.server.location.gnss.GnssMeasurementsProvider.GnssMeasurementProviderNative; -import com.android.server.location.gnss.GnssNavigationMessageProvider.GnssNavigationMessageProviderNative; -import com.android.server.location.injector.TestInjector; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.AdditionalMatchers; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; -import org.mockito.invocation.InvocationOnMock; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * Unit tests for {@link com.android.server.location.gnss.GnssManagerService}. - */ -public class GnssManagerServiceTest { - - private static final long TIMEOUT_MS = 5000; - private static final long FAILURE_TIMEOUT_MS = 200; - - private static final String TEST_PACKAGE = "com.test"; - - private TestInjector mInjector; - - @Mock private Handler mMockHandler; - @Mock private Context mMockContext; - @Mock private PackageManager mPackageManager; - @Mock private LocationManagerInternal mLocationManagerInternal; - @Mock private GnssNative.GnssNativeInitNative mGnssInitNative; - @Mock private GnssLocationProvider mMockGnssLocationProvider; - @Mock private GnssLocationProvider.GnssSystemInfoProvider mMockGnssSystemInfoProvider; - @Mock private GnssCapabilitiesProvider mMockGnssCapabilitiesProvider; - @Mock private GnssMeasurementCorrectionsProvider mMockGnssMeasurementCorrectionsProvider; - @Mock private INetInitiatedListener mNetInitiatedListener; - - private GnssMeasurementsProvider mTestGnssMeasurementsProvider; - private GnssStatusProvider mTestGnssStatusProvider; - private GnssNavigationMessageProvider mTestGnssNavigationMessageProvider; - private GnssAntennaInfoProvider mTestGnssAntennaInfoProvider; - - private GnssManagerService mGnssManagerService; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - - when(mGnssInitNative.isSupported()).thenReturn(true); - GnssNative.setInitNativeForTest(mGnssInitNative); - GnssNative.resetCallbacksForTest(); - - when(mMockContext.createAttributionContext(anyString())).thenReturn(mMockContext); - when(mMockContext.getPackageManager()).thenReturn(mPackageManager); - when(mPackageManager.getPackagesForUid(anyInt())).thenReturn( - new String[]{TEST_PACKAGE}); - - mInjector = new TestInjector(); - - enableLocationPermissions(); - - LocalServices.addService(LocationManagerInternal.class, mLocationManagerInternal); - - // Mock Handler will execute posted runnables immediately - when(mMockHandler.sendMessageAtTime(any(Message.class), anyLong())).thenAnswer( - (InvocationOnMock invocation) -> { - Message msg = (Message) (invocation.getArguments()[0]); - msg.getCallback().run(); - return null; - }); - - // Setup providers - mTestGnssMeasurementsProvider = createGnssMeasurementsProvider(); - mTestGnssStatusProvider = createGnssStatusListenerHelper(); - mTestGnssNavigationMessageProvider = createGnssNavigationMessageProvider(); - mTestGnssAntennaInfoProvider = createGnssAntennaInfoProvider(); - - // Setup GnssLocationProvider to return providers - when(mMockGnssLocationProvider.getGnssStatusProvider()).thenReturn( - mTestGnssStatusProvider); - when(mMockGnssLocationProvider.getGnssCapabilitiesProvider()).thenReturn( - mMockGnssCapabilitiesProvider); - when(mMockGnssLocationProvider.getGnssSystemInfoProvider()).thenReturn( - mMockGnssSystemInfoProvider); - when(mMockGnssLocationProvider.getGnssMeasurementCorrectionsProvider()).thenReturn( - mMockGnssMeasurementCorrectionsProvider); - when(mMockGnssLocationProvider.getGnssMeasurementsProvider()).thenReturn( - mTestGnssMeasurementsProvider); - when(mMockGnssLocationProvider.getGnssNavigationMessageProvider()).thenReturn( - mTestGnssNavigationMessageProvider); - when(mMockGnssLocationProvider.getNetInitiatedListener()).thenReturn( - mNetInitiatedListener); - when(mMockGnssLocationProvider.getGnssAntennaInfoProvider()).thenReturn( - mTestGnssAntennaInfoProvider); - - // Create GnssManagerService - mGnssManagerService = new GnssManagerService(mMockContext, mInjector, - mMockGnssLocationProvider); - mGnssManagerService.onSystemReady(); - } - - @After - public void tearDown() { - LocalServices.removeServiceForTest(LocationManagerInternal.class); - } - - private void overrideAsBinder(IInterface mockListener) { - IBinder mockBinder = mock(IBinder.class); - when(mockListener.asBinder()).thenReturn(mockBinder); - } - - private IGnssStatusListener createMockGnssStatusListener() { - IGnssStatusListener mockListener = mock(IGnssStatusListener.class); - overrideAsBinder(mockListener); - return mockListener; - } - - private IGnssMeasurementsListener createMockGnssMeasurementsListener() { - IGnssMeasurementsListener mockListener = mock( - IGnssMeasurementsListener.class); - overrideAsBinder(mockListener); - return mockListener; - } - - private IGnssAntennaInfoListener createMockGnssAntennaInfoListener() { - IGnssAntennaInfoListener mockListener = mock(IGnssAntennaInfoListener.class); - overrideAsBinder(mockListener); - return mockListener; - } - - private IGnssNavigationMessageListener createMockGnssNavigationMessageListener() { - IGnssNavigationMessageListener mockListener = mock(IGnssNavigationMessageListener.class); - overrideAsBinder(mockListener); - return mockListener; - } - - private GnssMeasurementCorrections createDummyGnssMeasurementCorrections() { - GnssSingleSatCorrection gnssSingleSatCorrection = - new GnssSingleSatCorrection.Builder().build(); - return - new GnssMeasurementCorrections.Builder().setSingleSatelliteCorrectionList( - Collections.singletonList(gnssSingleSatCorrection)).build(); - } - - private static List createDummyGnssAntennaInfos() { - double carrierFrequencyMHz = 13758.0; - - GnssAntennaInfo.PhaseCenterOffset phaseCenterOffset = new - GnssAntennaInfo.PhaseCenterOffset( - 4.3d, - 1.4d, - 2.10d, - 2.1d, - 3.12d, - 0.5d); - - double[][] phaseCenterVariationCorrectionsMillimeters = new double[10][10]; - double[][] phaseCenterVariationCorrectionsUncertaintyMillimeters = new double[10][10]; - SphericalCorrections - phaseCenterVariationCorrections = - new SphericalCorrections( - phaseCenterVariationCorrectionsMillimeters, - phaseCenterVariationCorrectionsUncertaintyMillimeters); - - double[][] signalGainCorrectionsDbi = new double[10][10]; - double[][] signalGainCorrectionsUncertaintyDbi = new double[10][10]; - SphericalCorrections signalGainCorrections = new - SphericalCorrections( - signalGainCorrectionsDbi, - signalGainCorrectionsUncertaintyDbi); - - List gnssAntennaInfos = new ArrayList<>(); - gnssAntennaInfos.add(new GnssAntennaInfo.Builder() - .setCarrierFrequencyMHz(carrierFrequencyMHz) - .setPhaseCenterOffset(phaseCenterOffset) - .setPhaseCenterVariationCorrections(phaseCenterVariationCorrections) - .setSignalGainCorrections(signalGainCorrections) - .build()); - return gnssAntennaInfos; - } - - private void enableLocationPermissions() { - Mockito.doThrow(new SecurityException()).when( - mMockContext).enforceCallingOrSelfPermission( - AdditionalMatchers.and( - AdditionalMatchers.not(eq(Manifest.permission.LOCATION_HARDWARE)), - AdditionalMatchers.not(eq(Manifest.permission.ACCESS_FINE_LOCATION))), - anyString()); - when(mMockContext.checkPermission( - eq(android.Manifest.permission.LOCATION_HARDWARE), anyInt(), anyInt())).thenReturn( - PackageManager.PERMISSION_GRANTED); - when(mMockContext.checkPermission( - eq(Manifest.permission.ACCESS_FINE_LOCATION), anyInt(), anyInt())).thenReturn( - PackageManager.PERMISSION_GRANTED); - when(mMockContext.checkPermission( - eq(Manifest.permission.ACCESS_COARSE_LOCATION), anyInt(), anyInt())).thenReturn( - PackageManager.PERMISSION_GRANTED); - - mInjector.getAppOpsHelper().setAppOpAllowed(OP_FINE_LOCATION, TEST_PACKAGE, true); - mInjector.getAppOpsHelper().setAppOpAllowed(OP_COARSE_LOCATION, TEST_PACKAGE, true); - - when(mLocationManagerInternal.isProviderEnabledForUser(eq(GPS_PROVIDER), anyInt())) - .thenReturn(true); - } - - private void disableLocationPermissions() { - Mockito.doThrow(new SecurityException()).when( - mMockContext).enforceCallingOrSelfPermission(anyString(), nullable(String.class)); - - when(mMockContext.checkPermission( - anyString(), anyInt(), anyInt())).thenReturn( - PackageManager.PERMISSION_DENIED); - - mInjector.getAppOpsHelper().setAppOpAllowed(OP_FINE_LOCATION, TEST_PACKAGE, false); - mInjector.getAppOpsHelper().setAppOpAllowed(OP_COARSE_LOCATION, TEST_PACKAGE, false); - - when(mLocationManagerInternal.isProviderEnabledForUser(eq(GPS_PROVIDER), anyInt())) - .thenReturn(false); - } - - private GnssStatusProvider createGnssStatusListenerHelper() { - return new GnssStatusProvider(mInjector); - } - - private GnssMeasurementsProvider createGnssMeasurementsProvider() { - GnssMeasurementProviderNative - mockGnssMeasurementProviderNative = mock(GnssMeasurementProviderNative.class); - when(mockGnssMeasurementProviderNative.isMeasurementSupported()).thenReturn( - true); - return new GnssMeasurementsProvider(mInjector, mockGnssMeasurementProviderNative); - } - - private GnssNavigationMessageProvider createGnssNavigationMessageProvider() { - GnssNavigationMessageProviderNative mockGnssNavigationMessageProviderNative = mock( - GnssNavigationMessageProviderNative.class); - when(mockGnssNavigationMessageProviderNative.isNavigationMessageSupported()).thenReturn( - true); - return new GnssNavigationMessageProvider(mInjector, - mockGnssNavigationMessageProviderNative); - } - - private GnssAntennaInfoProvider createGnssAntennaInfoProvider() { - GnssAntennaInfoProviderNative mockGnssAntenaInfoProviderNative = mock( - GnssAntennaInfoProviderNative.class); - when(mockGnssAntenaInfoProviderNative.isAntennaInfoSupported()).thenReturn( - true); - return new GnssAntennaInfoProvider(mInjector, mockGnssAntenaInfoProviderNative); - } - - @Test - public void getGnssYearOfHardwareTest() { - final int gnssYearOfHardware = 2012; - when(mMockGnssSystemInfoProvider.getGnssYearOfHardware()).thenReturn(gnssYearOfHardware); - enableLocationPermissions(); - - assertThat(mGnssManagerService.getGnssYearOfHardware()).isEqualTo(gnssYearOfHardware); - } - - @Test - public void getGnssHardwareModelNameTest() { - final String gnssHardwareModelName = "hardwarename"; - when(mMockGnssSystemInfoProvider.getGnssHardwareModelName()).thenReturn( - gnssHardwareModelName); - enableLocationPermissions(); - - assertThat(mGnssManagerService.getGnssHardwareModelName()).isEqualTo( - gnssHardwareModelName); - } - - @Test - public void getGnssCapabilitiesWithPermissionsTest() { - final long mGnssCapabilities = 23132L; - when(mMockGnssCapabilitiesProvider.getGnssCapabilities()).thenReturn(mGnssCapabilities); - enableLocationPermissions(); - - assertThat(mGnssManagerService.getGnssCapabilities()).isEqualTo(mGnssCapabilities); - } - - @Test - public void registerGnssStatusCallbackWithoutPermissionsTest() throws RemoteException { - final int timeToFirstFix = 20000; - IGnssStatusListener mockGnssStatusListener = createMockGnssStatusListener(); - - disableLocationPermissions(); - - assertThrows(SecurityException.class, () -> mGnssManagerService - .registerGnssStatusCallback( - mockGnssStatusListener, TEST_PACKAGE, "abcd123")); - - mTestGnssStatusProvider.onFirstFix(timeToFirstFix); - - verify(mockGnssStatusListener, after(FAILURE_TIMEOUT_MS).times(0)).onFirstFix( - timeToFirstFix); - } - - @Test - public void registerGnssStatusCallbackWithPermissionsTest() throws RemoteException { - final int timeToFirstFix = 20000; - IGnssStatusListener mockGnssStatusListener = createMockGnssStatusListener(); - - enableLocationPermissions(); - - mGnssManagerService.registerGnssStatusCallback( - mockGnssStatusListener, TEST_PACKAGE, "abcd123"); - - mTestGnssStatusProvider.onFirstFix(timeToFirstFix); - - verify(mockGnssStatusListener, timeout(TIMEOUT_MS).times(1)).onFirstFix(timeToFirstFix); - } - - @Test - public void unregisterGnssStatusCallbackWithPermissionsTest() throws RemoteException { - final int timeToFirstFix = 20000; - IGnssStatusListener mockGnssStatusListener = createMockGnssStatusListener(); - - enableLocationPermissions(); - - mGnssManagerService.registerGnssStatusCallback( - mockGnssStatusListener, TEST_PACKAGE, "abcd123"); - - mGnssManagerService.unregisterGnssStatusCallback(mockGnssStatusListener); - - mTestGnssStatusProvider.onFirstFix(timeToFirstFix); - - verify(mockGnssStatusListener, after(FAILURE_TIMEOUT_MS).times(0)).onFirstFix( - timeToFirstFix); - } - - @Test - public void addGnssMeasurementsListenerWithoutPermissionsTest() throws RemoteException { - IGnssMeasurementsListener mockGnssMeasurementsListener = - createMockGnssMeasurementsListener(); - GnssMeasurementsEvent gnssMeasurementsEvent = new GnssMeasurementsEvent(new GnssClock(), - null); - - disableLocationPermissions(); - - assertThrows(SecurityException.class, - () -> mGnssManagerService.addGnssMeasurementsListener( - new GnssMeasurementRequest.Builder().build(), mockGnssMeasurementsListener, - TEST_PACKAGE, null)); - - mTestGnssMeasurementsProvider.onMeasurementsAvailable(gnssMeasurementsEvent); - verify(mockGnssMeasurementsListener, - after(FAILURE_TIMEOUT_MS).times(0)).onGnssMeasurementsReceived( - gnssMeasurementsEvent); - } - - @Test - public void addGnssMeasurementsListenerWithPermissionsTest() throws RemoteException { - IGnssMeasurementsListener mockGnssMeasurementsListener = - createMockGnssMeasurementsListener(); - GnssMeasurementsEvent gnssMeasurementsEvent = new GnssMeasurementsEvent(new GnssClock(), - null); - - enableLocationPermissions(); - - mGnssManagerService.addGnssMeasurementsListener( - new GnssMeasurementRequest.Builder().build(), - mockGnssMeasurementsListener, - TEST_PACKAGE, null); - - mTestGnssMeasurementsProvider.onMeasurementsAvailable(gnssMeasurementsEvent); - verify(mockGnssMeasurementsListener, - timeout(TIMEOUT_MS).times(1)).onGnssMeasurementsReceived( - gnssMeasurementsEvent); - } - - @Test - public void injectGnssMeasurementCorrectionsWithoutPermissionsTest() { - GnssMeasurementCorrections gnssMeasurementCorrections = - createDummyGnssMeasurementCorrections(); - - disableLocationPermissions(); - - assertThrows(SecurityException.class, - () -> mGnssManagerService.injectGnssMeasurementCorrections( - gnssMeasurementCorrections)); - verify(mMockGnssMeasurementCorrectionsProvider, times(0)) - .injectGnssMeasurementCorrections( - gnssMeasurementCorrections); - } - - @Test - public void injectGnssMeasurementCorrectionsWithPermissionsTest() { - GnssMeasurementCorrections gnssMeasurementCorrections = - createDummyGnssMeasurementCorrections(); - - enableLocationPermissions(); - - mGnssManagerService.injectGnssMeasurementCorrections( - gnssMeasurementCorrections); - verify(mMockGnssMeasurementCorrectionsProvider, times(1)) - .injectGnssMeasurementCorrections( - gnssMeasurementCorrections); - } - - @Test - public void removeGnssMeasurementsListenerWithoutPermissionsTest() throws RemoteException { - IGnssMeasurementsListener mockGnssMeasurementsListener = - createMockGnssMeasurementsListener(); - GnssMeasurementsEvent gnssMeasurementsEvent = new GnssMeasurementsEvent(new GnssClock(), - null); - - enableLocationPermissions(); - - mGnssManagerService.addGnssMeasurementsListener( - new GnssMeasurementRequest.Builder().build(), - mockGnssMeasurementsListener, - TEST_PACKAGE, null); - - disableLocationPermissions(); - - mGnssManagerService.removeGnssMeasurementsListener( - mockGnssMeasurementsListener); - - mTestGnssMeasurementsProvider.onMeasurementsAvailable(gnssMeasurementsEvent); - verify(mockGnssMeasurementsListener, - after(FAILURE_TIMEOUT_MS).times(0)).onGnssMeasurementsReceived( - gnssMeasurementsEvent); - } - - @Test - public void removeGnssMeasurementsListenerWithPermissionsTest() throws RemoteException { - IGnssMeasurementsListener mockGnssMeasurementsListener = - createMockGnssMeasurementsListener(); - GnssMeasurementsEvent gnssMeasurementsEvent = new GnssMeasurementsEvent(new GnssClock(), - null); - - enableLocationPermissions(); - - mGnssManagerService.addGnssMeasurementsListener( - new GnssMeasurementRequest.Builder().build(), - mockGnssMeasurementsListener, - TEST_PACKAGE, null); - - disableLocationPermissions(); - - mGnssManagerService.removeGnssMeasurementsListener( - mockGnssMeasurementsListener); - - mTestGnssMeasurementsProvider.onMeasurementsAvailable(gnssMeasurementsEvent); - verify(mockGnssMeasurementsListener, - after(FAILURE_TIMEOUT_MS).times(0)).onGnssMeasurementsReceived( - gnssMeasurementsEvent); - } - - @Test - public void addGnssAntennaInfoListenerWithoutPermissionsTest() throws RemoteException { - IGnssAntennaInfoListener mockGnssAntennaInfoListener = - createMockGnssAntennaInfoListener(); - List gnssAntennaInfos = createDummyGnssAntennaInfos(); - - disableLocationPermissions(); - - assertThrows(SecurityException.class, - () -> mGnssManagerService.addGnssAntennaInfoListener( - mockGnssAntennaInfoListener, - TEST_PACKAGE, null)); - - mTestGnssAntennaInfoProvider.onGnssAntennaInfoAvailable(gnssAntennaInfos); - verify(mockGnssAntennaInfoListener, after(FAILURE_TIMEOUT_MS).times(0)) - .onGnssAntennaInfoReceived(gnssAntennaInfos); - } - - @Test - public void addGnssAntennaInfoListenerWithPermissionsTest() throws RemoteException { - IGnssAntennaInfoListener mockGnssAntennaInfoListener = - createMockGnssAntennaInfoListener(); - List gnssAntennaInfos = createDummyGnssAntennaInfos(); - - enableLocationPermissions(); - - mGnssManagerService.addGnssAntennaInfoListener(mockGnssAntennaInfoListener, - TEST_PACKAGE, null); - - mTestGnssAntennaInfoProvider.onGnssAntennaInfoAvailable(gnssAntennaInfos); - verify(mockGnssAntennaInfoListener, timeout(TIMEOUT_MS).times(1)) - .onGnssAntennaInfoReceived(gnssAntennaInfos); - } - - @Test - public void removeGnssAntennaInfoListenerWithoutPermissionsTest() throws RemoteException { - IGnssAntennaInfoListener mockGnssAntennaInfoListener = - createMockGnssAntennaInfoListener(); - List gnssAntennaInfos = createDummyGnssAntennaInfos(); - - enableLocationPermissions(); - - mGnssManagerService.addGnssAntennaInfoListener( - mockGnssAntennaInfoListener, - TEST_PACKAGE, null); - - disableLocationPermissions(); - - mGnssManagerService.removeGnssAntennaInfoListener( - mockGnssAntennaInfoListener); - - mTestGnssAntennaInfoProvider.onGnssAntennaInfoAvailable(gnssAntennaInfos); - verify(mockGnssAntennaInfoListener, after(FAILURE_TIMEOUT_MS).times(0)) - .onGnssAntennaInfoReceived(gnssAntennaInfos); - } - - @Test - public void removeGnssAntennaInfoListenerWithPermissionsTest() throws RemoteException { - IGnssAntennaInfoListener mockGnssAntennaInfoListener = - createMockGnssAntennaInfoListener(); - List gnssAntennaInfos = createDummyGnssAntennaInfos(); - - enableLocationPermissions(); - - mGnssManagerService.addGnssAntennaInfoListener( - mockGnssAntennaInfoListener, - TEST_PACKAGE, null); - - mGnssManagerService.removeGnssAntennaInfoListener( - mockGnssAntennaInfoListener); - - mTestGnssAntennaInfoProvider.onGnssAntennaInfoAvailable(gnssAntennaInfos); - verify(mockGnssAntennaInfoListener, - after(FAILURE_TIMEOUT_MS).times(0)).onGnssAntennaInfoReceived( - gnssAntennaInfos); - } - - @Test - public void addGnssNavigationMessageListenerWithoutPermissionsTest() throws RemoteException { - IGnssNavigationMessageListener mockGnssNavigationMessageListener = - createMockGnssNavigationMessageListener(); - GnssNavigationMessage gnssNavigationMessage = new GnssNavigationMessage(); - - disableLocationPermissions(); - - assertThrows(SecurityException.class, - () -> mGnssManagerService.addGnssNavigationMessageListener( - mockGnssNavigationMessageListener, TEST_PACKAGE, null)); - - mTestGnssNavigationMessageProvider.onNavigationMessageAvailable(gnssNavigationMessage); - - verify(mockGnssNavigationMessageListener, - after(FAILURE_TIMEOUT_MS).times(0)).onGnssNavigationMessageReceived( - gnssNavigationMessage); - } - - @Test - public void addGnssNavigationMessageListenerWithPermissionsTest() throws RemoteException { - IGnssNavigationMessageListener mockGnssNavigationMessageListener = - createMockGnssNavigationMessageListener(); - GnssNavigationMessage gnssNavigationMessage = new GnssNavigationMessage(); - - enableLocationPermissions(); - - mGnssManagerService.addGnssNavigationMessageListener( - mockGnssNavigationMessageListener, TEST_PACKAGE, null); - - mTestGnssNavigationMessageProvider.onNavigationMessageAvailable(gnssNavigationMessage); - - verify(mockGnssNavigationMessageListener, - timeout(TIMEOUT_MS).times(1)).onGnssNavigationMessageReceived( - gnssNavigationMessage); - } - - @Test - public void removeGnssNavigationMessageListenerWithoutPermissionsTest() throws RemoteException { - IGnssNavigationMessageListener mockGnssNavigationMessageListener = - createMockGnssNavigationMessageListener(); - GnssNavigationMessage gnssNavigationMessage = new GnssNavigationMessage(); - - enableLocationPermissions(); - - mGnssManagerService.addGnssNavigationMessageListener( - mockGnssNavigationMessageListener, TEST_PACKAGE, null); - - disableLocationPermissions(); - - mGnssManagerService.removeGnssNavigationMessageListener( - mockGnssNavigationMessageListener); - - mTestGnssNavigationMessageProvider.onNavigationMessageAvailable(gnssNavigationMessage); - - verify(mockGnssNavigationMessageListener, - after(FAILURE_TIMEOUT_MS).times(0)).onGnssNavigationMessageReceived( - gnssNavigationMessage); - } - - @Test - public void removeGnssNavigationMessageListenerWithPermissionsTest() throws RemoteException { - IGnssNavigationMessageListener mockGnssNavigationMessageListener = - createMockGnssNavigationMessageListener(); - GnssNavigationMessage gnssNavigationMessage = new GnssNavigationMessage(); - - enableLocationPermissions(); - - mGnssManagerService.addGnssNavigationMessageListener( - mockGnssNavigationMessageListener, TEST_PACKAGE, null); - - mGnssManagerService.removeGnssNavigationMessageListener( - mockGnssNavigationMessageListener); - - mTestGnssNavigationMessageProvider.onNavigationMessageAvailable(gnssNavigationMessage); - - verify(mockGnssNavigationMessageListener, - after(FAILURE_TIMEOUT_MS).times(0)).onGnssNavigationMessageReceived( - gnssNavigationMessage); - } - - @Test - public void sendNiResponseWithPermissionsTest() throws RemoteException { - int notifId = 0; - int userResponse = 0; - enableLocationPermissions(); - - mGnssManagerService.sendNiResponse(notifId, userResponse); - - verify(mNetInitiatedListener, times(1)).sendNiResponse(notifId, userResponse); - } -} diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java new file mode 100644 index 0000000000000..675274bf82c4e --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java @@ -0,0 +1,674 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.location.gnss.hal; + +import static com.android.server.location.gnss.hal.GnssNative.GNSS_LOCATION_HAS_ALTITUDE; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_LOCATION_HAS_BEARING; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_LOCATION_HAS_BEARING_ACCURACY; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_LOCATION_HAS_HORIZONTAL_ACCURACY; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_LOCATION_HAS_LAT_LONG; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_LOCATION_HAS_SPEED; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_LOCATION_HAS_SPEED_ACCURACY; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_LOCATION_HAS_VERTICAL_ACCURACY; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_REALTIME_HAS_TIMESTAMP_NS; +import static com.android.server.location.gnss.hal.GnssNative.GNSS_REALTIME_HAS_TIME_UNCERTAINTY_NS; +import static com.android.server.location.gnss.hal.GnssNative.GeofenceCallbacks.GEOFENCE_STATUS_ERROR_ID_EXISTS; +import static com.android.server.location.gnss.hal.GnssNative.GeofenceCallbacks.GEOFENCE_STATUS_ERROR_ID_UNKNOWN; +import static com.android.server.location.gnss.hal.GnssNative.GeofenceCallbacks.GEOFENCE_STATUS_OPERATION_SUCCESS; +import static com.android.server.location.gnss.hal.GnssNative.GeofenceCallbacks.GEOFENCE_TRANSITION_ENTERED; +import static com.android.server.location.gnss.hal.GnssNative.GeofenceCallbacks.GEOFENCE_TRANSITION_EXITED; + +import android.annotation.Nullable; +import android.location.GnssAntennaInfo; +import android.location.GnssMeasurementCorrections; +import android.location.GnssMeasurementsEvent; +import android.location.GnssNavigationMessage; +import android.location.Location; + +import com.android.server.location.gnss.GnssPowerStats; +import com.android.server.location.gnss.hal.GnssNative.GnssLocationFlags; +import com.android.server.location.gnss.hal.GnssNative.GnssRealtimeFlags; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Objects; + +/** + * Fake GNSS HAL for testing. + */ +public final class FakeGnssHal extends GnssNative.GnssHal { + + public static class GnssHalPositionMode { + + public final int Mode; + public final int Recurrence; + public final int MinInterval; + public final int PreferredAccuracy; + public final int PreferredTime; + public final boolean LowPowerMode; + + GnssHalPositionMode() { + Mode = 0; + Recurrence = 0; + MinInterval = 0; + PreferredAccuracy = 0; + PreferredTime = 0; + LowPowerMode = false; + } + + public GnssHalPositionMode(int mode, int recurrence, int minInterval, int preferredAccuracy, + int preferredTime, boolean lowPowerMode) { + Mode = mode; + Recurrence = recurrence; + MinInterval = minInterval; + PreferredAccuracy = preferredAccuracy; + PreferredTime = preferredTime; + LowPowerMode = lowPowerMode; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + GnssHalPositionMode that = (GnssHalPositionMode) o; + return Mode == that.Mode + && Recurrence == that.Recurrence + && MinInterval == that.MinInterval + && PreferredAccuracy == that.PreferredAccuracy + && PreferredTime == that.PreferredTime + && LowPowerMode == that.LowPowerMode; + } + + @Override + public int hashCode() { + return Objects.hash(Recurrence, MinInterval); + } + } + + public static class GnssHalBatchingMode { + + public final long PeriodNanos; + public final boolean WakeOnFifoFull; + + GnssHalBatchingMode() { + PeriodNanos = 0; + WakeOnFifoFull = false; + } + + public GnssHalBatchingMode(long periodNanos, boolean wakeOnFifoFull) { + PeriodNanos = periodNanos; + WakeOnFifoFull = wakeOnFifoFull; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + GnssHalBatchingMode that = (GnssHalBatchingMode) o; + return PeriodNanos == that.PeriodNanos + && WakeOnFifoFull == that.WakeOnFifoFull; + } + + @Override + public int hashCode() { + return Objects.hash(PeriodNanos, WakeOnFifoFull); + } + } + + public static class GnssHalInjectedTime { + + public final long Time; + public final long TimeReference; + public final int Uncertainty; + + public GnssHalInjectedTime(long time, long timeReference, int uncertainty) { + Time = time; + TimeReference = timeReference; + Uncertainty = uncertainty; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + GnssHalInjectedTime that = (GnssHalInjectedTime) o; + return Time == that.Time + && TimeReference == that.TimeReference + && Uncertainty == that.Uncertainty; + } + + @Override + public int hashCode() { + return Objects.hash(Time); + } + } + + public static class GnssHalGeofence { + + public final int GeofenceId; + public final Location Center; + public final double Radius; + public int LastTransition; + public int MonitorTransitions; + public final int NotificationResponsiveness; + public final int UnknownTimer; + public boolean Paused; + + public GnssHalGeofence(int geofenceId, double latitude, double longitude, double radius, + int lastTransition, int monitorTransitions, int notificationResponsiveness, + int unknownTimer, boolean paused) { + GeofenceId = geofenceId; + Center = new Location(""); + Center.setLatitude(latitude); + Center.setLongitude(longitude); + Radius = radius; + LastTransition = lastTransition; + MonitorTransitions = monitorTransitions; + NotificationResponsiveness = notificationResponsiveness; + UnknownTimer = unknownTimer; + Paused = paused; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + GnssHalGeofence that = (GnssHalGeofence) o; + return GeofenceId == that.GeofenceId + && Double.compare(that.Radius, Radius) == 0 + && LastTransition == that.LastTransition + && MonitorTransitions == that.MonitorTransitions + && NotificationResponsiveness == that.NotificationResponsiveness + && UnknownTimer == that.UnknownTimer + && Paused == that.Paused + && Center.equals(that.Center); + } + + @Override + public int hashCode() { + return Objects.hash(GeofenceId); + } + } + + private static class HalState { + private boolean mStarted = false; + private boolean mBatchingStarted = false; + private boolean mNavigationMessagesStarted = false; + private boolean mAntennaInfoListeningStarted = false; + private boolean mMeasurementCollectionStarted = false; + private boolean mMeasurementCollectionFullTracking = false; + private GnssHalPositionMode mPositionMode = new GnssHalPositionMode(); + private GnssHalBatchingMode mBatchingMode = new GnssHalBatchingMode(); + private final ArrayList mBatchedLocations = new ArrayList<>(); + private Location mInjectedLocation = null; + private Location mInjectedBestLocation = null; + private GnssHalInjectedTime mInjectedTime = null; + private GnssMeasurementCorrections mInjectedMeasurementCorrections = null; + private final HashMap mGeofences = new HashMap<>(); + private GnssPowerStats mPowerStats = new GnssPowerStats(0, 0, 0, 0, 0, 0, 0, 0, + new double[0]); + } + + private @Nullable GnssNative mGnssNative; + private HalState mState = new HalState(); + + private boolean mIsNavigationMessageCollectionSupported = true; + private boolean mIsAntennaInfoListeningSupported = true; + private boolean mIsMeasurementSupported = true; + private boolean mIsMeasurementCorrectionsSupported = true; + private int mBatchSize = 0; + private boolean mIsGeofencingSupported = true; + private boolean mIsVisibilityControlSupported = true; + + public FakeGnssHal() {} + + public void restartHal() { + mState = new HalState(); + Objects.requireNonNull(mGnssNative).restartHal(); + } + + public void setIsNavigationMessageCollectionSupported(boolean supported) { + mIsNavigationMessageCollectionSupported = supported; + } + + public void setIsAntennaInfoListeningSupported(boolean supported) { + mIsAntennaInfoListeningSupported = supported; + } + + public void setIsMeasurementSupported(boolean supported) { + mIsMeasurementSupported = supported; + } + + public void setIsMeasurementCorrectionsSupported(boolean supported) { + mIsMeasurementCorrectionsSupported = supported; + } + + public void setBatchSize(int batchSize) { + mBatchSize = batchSize; + } + + public void setIsGeofencingSupported(boolean supported) { + mIsGeofencingSupported = supported; + } + + public void setPowerStats(GnssPowerStats powerStats) { + mState.mPowerStats = powerStats; + } + + public void setIsVisibilityControlSupported(boolean supported) { + mIsVisibilityControlSupported = supported; + } + + public GnssHalPositionMode getPositionMode() { + return mState.mPositionMode; + } + + public void reportLocation(Location location) { + if (mState.mStarted) { + Objects.requireNonNull(mGnssNative).reportLocation(true, location); + } + if (mState.mBatchingStarted) { + mState.mBatchedLocations.add(location); + if (mState.mBatchedLocations.size() >= mBatchSize) { + if (mState.mBatchingMode.WakeOnFifoFull) { + flushBatch(); + } else { + mState.mBatchedLocations.remove(0); + } + } + } + for (GnssHalGeofence geofence : mState.mGeofences.values()) { + if (!geofence.Paused) { + if (geofence.Center.distanceTo(location) > geofence.Radius) { + if (geofence.LastTransition != GEOFENCE_TRANSITION_EXITED) { + geofence.LastTransition = GEOFENCE_TRANSITION_EXITED; + if ((geofence.MonitorTransitions & GEOFENCE_TRANSITION_EXITED) != 0) { + Objects.requireNonNull(mGnssNative).reportGeofenceTransition( + geofence.GeofenceId, location, GEOFENCE_TRANSITION_EXITED, + location.getTime()); + } + } + } else { + if (geofence.LastTransition != GEOFENCE_TRANSITION_ENTERED) { + geofence.LastTransition = GEOFENCE_TRANSITION_ENTERED; + if ((geofence.MonitorTransitions & GEOFENCE_TRANSITION_ENTERED) != 0) { + Objects.requireNonNull(mGnssNative).reportGeofenceTransition( + geofence.GeofenceId, location, GEOFENCE_TRANSITION_ENTERED, + location.getTime()); + } + } + } + } + } + } + + public void reportNavigationMessage(GnssNavigationMessage message) { + if (mState.mNavigationMessagesStarted) { + Objects.requireNonNull(mGnssNative).reportNavigationMessage(message); + } + } + + public void reportAntennaInfo(List antennaInfos) { + if (mState.mAntennaInfoListeningStarted) { + Objects.requireNonNull(mGnssNative).reportAntennaInfo(antennaInfos); + } + } + + public boolean isMeasurementCollectionFullTracking() { + return mState.mMeasurementCollectionFullTracking; + } + + public void reportMeasurement(GnssMeasurementsEvent event) { + if (mState.mMeasurementCollectionStarted) { + Objects.requireNonNull(mGnssNative).reportMeasurementData(event); + } + } + + public GnssHalInjectedTime getLastInjectedTime() { + return mState.mInjectedTime; + } + + public GnssMeasurementCorrections getLastInjectedCorrections() { + return mState.mInjectedMeasurementCorrections; + } + + public Collection getGeofences() { + return mState.mGeofences.values(); + } + + @Override + protected void classInitOnce() {} + + @Override + protected boolean isSupported() { + return true; + } + + @Override + protected void initOnce(GnssNative gnssNative, boolean reinitializeGnssServiceHandle) { + mGnssNative = Objects.requireNonNull(gnssNative); + } + + @Override + protected boolean init() { + return true; + } + + @Override + protected void cleanup() {} + + @Override + protected boolean start() { + mState.mStarted = true; + return true; + } + + @Override + protected boolean stop() { + mState.mStarted = false; + return true; + } + + @Override + protected boolean setPositionMode(int mode, int recurrence, int minInterval, + int preferredAccuracy, int preferredTime, boolean lowPowerMode) { + mState.mPositionMode = new GnssHalPositionMode(mode, recurrence, minInterval, + preferredAccuracy, preferredTime, lowPowerMode); + return true; + } + + @Override + protected String getInternalState() { + return "DebugState"; + } + + @Override + protected void deleteAidingData(int flags) {} + + @Override + protected int readNmea(byte[] buffer, int bufferSize) { + return 0; + } + + @Override + protected void injectLocation(double latitude, double longitude, float accuracy) { + mState.mInjectedLocation = new Location("injected"); + mState.mInjectedLocation.setLatitude(latitude); + mState.mInjectedLocation.setLongitude(longitude); + mState.mInjectedLocation.setAccuracy(accuracy); + } + + @Override + protected void injectBestLocation(@GnssLocationFlags int gnssLocationFlags, double latitude, + double longitude, double altitude, float speed, float bearing, float horizontalAccuracy, + float verticalAccuracy, float speedAccuracy, float bearingAccuracy, long timestamp, + @GnssRealtimeFlags int elapsedRealtimeFlags, long elapsedRealtimeNanos, + double elapsedRealtimeUncertaintyNanos) { + mState.mInjectedBestLocation = new Location("injectedBest"); + if ((gnssLocationFlags & GNSS_LOCATION_HAS_LAT_LONG) != 0) { + mState.mInjectedBestLocation.setLatitude(latitude); + mState.mInjectedBestLocation.setLongitude(longitude); + } + if ((gnssLocationFlags & GNSS_LOCATION_HAS_ALTITUDE) != 0) { + mState.mInjectedBestLocation.setAltitude(altitude); + } + if ((gnssLocationFlags & GNSS_LOCATION_HAS_SPEED) != 0) { + mState.mInjectedBestLocation.setSpeed(speed); + } + if ((gnssLocationFlags & GNSS_LOCATION_HAS_BEARING) != 0) { + mState.mInjectedBestLocation.setBearing(bearing); + } + if ((gnssLocationFlags & GNSS_LOCATION_HAS_HORIZONTAL_ACCURACY) != 0) { + mState.mInjectedBestLocation.setAccuracy(horizontalAccuracy); + } + if ((gnssLocationFlags & GNSS_LOCATION_HAS_VERTICAL_ACCURACY) != 0) { + mState.mInjectedBestLocation.setVerticalAccuracyMeters(verticalAccuracy); + } + if ((gnssLocationFlags & GNSS_LOCATION_HAS_SPEED_ACCURACY) != 0) { + mState.mInjectedBestLocation.setSpeedAccuracyMetersPerSecond(speedAccuracy); + } + if ((gnssLocationFlags & GNSS_LOCATION_HAS_BEARING_ACCURACY) != 0) { + mState.mInjectedBestLocation.setBearingAccuracyDegrees(bearingAccuracy); + } + mState.mInjectedBestLocation.setTime(timestamp); + if ((elapsedRealtimeFlags & GNSS_REALTIME_HAS_TIMESTAMP_NS) != 0) { + mState.mInjectedBestLocation.setElapsedRealtimeNanos(elapsedRealtimeNanos); + } + if ((elapsedRealtimeFlags & GNSS_REALTIME_HAS_TIME_UNCERTAINTY_NS) != 0) { + mState.mInjectedBestLocation.setElapsedRealtimeUncertaintyNanos( + elapsedRealtimeUncertaintyNanos); + } + } + + @Override + protected void injectTime(long time, long timeReference, int uncertainty) { + mState.mInjectedTime = new GnssHalInjectedTime(time, timeReference, uncertainty); + } + + @Override + protected boolean isNavigationMessageCollectionSupported() { + return mIsNavigationMessageCollectionSupported; + } + + @Override + protected boolean startNavigationMessageCollection() { + mState.mNavigationMessagesStarted = true; + return true; + } + + @Override + protected boolean stopNavigationMessageCollection() { + mState.mNavigationMessagesStarted = false; + return true; + } + + @Override + protected boolean isAntennaInfoListeningSupported() { + return mIsAntennaInfoListeningSupported; + } + + @Override + protected boolean startAntennaInfoListening() { + mState.mAntennaInfoListeningStarted = true; + return true; + } + + @Override + protected boolean stopAntennaInfoListening() { + mState.mAntennaInfoListeningStarted = false; + return true; + } + + @Override + protected boolean isMeasurementSupported() { + return mIsMeasurementSupported; + } + + @Override + protected boolean startMeasurementCollection(boolean enableFullTracking) { + mState.mMeasurementCollectionStarted = true; + mState.mMeasurementCollectionFullTracking = enableFullTracking; + return true; + } + + @Override + protected boolean stopMeasurementCollection() { + mState.mMeasurementCollectionStarted = false; + mState.mMeasurementCollectionFullTracking = false; + return true; + } + + @Override + protected boolean isMeasurementCorrectionsSupported() { + return mIsMeasurementCorrectionsSupported; + } + + @Override + protected boolean injectMeasurementCorrections(GnssMeasurementCorrections corrections) { + mState.mInjectedMeasurementCorrections = corrections; + return true; + } + + @Override + protected int getBatchSize() { + return mBatchSize; + } + + @Override + protected boolean initBatching() { + return true; + } + + @Override + protected void cleanupBatching() {} + + @Override + protected boolean startBatch(long periodNanos, boolean wakeOnFifoFull) { + mState.mBatchingStarted = true; + mState.mBatchingMode = new GnssHalBatchingMode(periodNanos, wakeOnFifoFull); + return true; + } + + @Override + protected void flushBatch() { + Location[] locations = mState.mBatchedLocations.toArray(new Location[0]); + mState.mBatchedLocations.clear(); + Objects.requireNonNull(mGnssNative).reportLocationBatch(locations); + } + + @Override + protected void stopBatch() { + mState.mBatchingStarted = false; + mState.mBatchingMode = new GnssHalBatchingMode(); + mState.mBatchedLocations.clear(); + } + + @Override + protected boolean isGeofencingSupported() { + return mIsGeofencingSupported; + } + + @Override + protected boolean addGeofence(int geofenceId, double latitude, double longitude, double radius, + int lastTransition, int monitorTransitions, int notificationResponsiveness, + int unknownTimer) { + if (mState.mGeofences.containsKey(geofenceId)) { + Objects.requireNonNull(mGnssNative).reportGeofenceAddStatus(geofenceId, + GEOFENCE_STATUS_ERROR_ID_EXISTS); + } else { + mState.mGeofences.put(geofenceId, + new GnssHalGeofence(geofenceId, latitude, longitude, radius, lastTransition, + monitorTransitions, notificationResponsiveness, unknownTimer, false)); + Objects.requireNonNull(mGnssNative).reportGeofenceAddStatus(geofenceId, + GEOFENCE_STATUS_OPERATION_SUCCESS); + } + return true; + } + + @Override + protected boolean resumeGeofence(int geofenceId, int monitorTransitions) { + GnssHalGeofence geofence = mState.mGeofences.get(geofenceId); + if (geofence != null) { + geofence.Paused = false; + geofence.MonitorTransitions = monitorTransitions; + Objects.requireNonNull(mGnssNative).reportGeofenceAddStatus(geofenceId, + GEOFENCE_STATUS_OPERATION_SUCCESS); + } else { + Objects.requireNonNull(mGnssNative).reportGeofenceAddStatus(geofenceId, + GEOFENCE_STATUS_ERROR_ID_UNKNOWN); + } + return true; + } + + @Override + protected boolean pauseGeofence(int geofenceId) { + GnssHalGeofence geofence = mState.mGeofences.get(geofenceId); + if (geofence != null) { + geofence.Paused = true; + Objects.requireNonNull(mGnssNative).reportGeofenceAddStatus(geofenceId, + GEOFENCE_STATUS_OPERATION_SUCCESS); + } else { + Objects.requireNonNull(mGnssNative).reportGeofenceAddStatus(geofenceId, + GEOFENCE_STATUS_ERROR_ID_UNKNOWN); + } + return true; + } + + @Override + protected boolean removeGeofence(int geofenceId) { + if (mState.mGeofences.remove(geofenceId) != null) { + Objects.requireNonNull(mGnssNative).reportGeofenceRemoveStatus(geofenceId, + GEOFENCE_STATUS_OPERATION_SUCCESS); + } else { + Objects.requireNonNull(mGnssNative).reportGeofenceRemoveStatus(geofenceId, + GEOFENCE_STATUS_ERROR_ID_UNKNOWN); + } + return true; + } + + @Override + protected boolean isGnssVisibilityControlSupported() { + return mIsVisibilityControlSupported; + } + + @Override + protected void sendNiResponse(int notificationId, int userResponse) {} + + @Override + protected void requestPowerStats() { + Objects.requireNonNull(mGnssNative).reportGnssPowerStats(mState.mPowerStats); + } + + @Override + protected void setAgpsServer(int type, String hostname, int port) {} + + @Override + protected void setAgpsSetId(int type, String setId) {} + + @Override + protected void setAgpsReferenceLocationCellId(int type, int mcc, int mnc, int lac, int cid) {} + + @Override + protected boolean isPsdsSupported() { + return true; + } + + @Override + protected void injectPsdsData(byte[] data, int length, int psdsType) {} +} diff --git a/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeEmergencyHelper.java b/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeEmergencyHelper.java new file mode 100644 index 0000000000000..2cf57dafc7d9a --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeEmergencyHelper.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.location.injector; + +/** + * Version of EmergencyHelper for testing. + */ +public class FakeEmergencyHelper extends EmergencyHelper { + + private boolean mInEmergency; + + public FakeEmergencyHelper() {} + + public void setInEmergency(boolean inEmergency) { + mInEmergency = inEmergency; + } + + @Override + public boolean isInEmergency(long extensionTimeMs) { + return mInEmergency; + } +} diff --git a/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java b/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java index f3c31c2cdd2b7..8e5b16e1ee3ac 100644 --- a/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java +++ b/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java @@ -28,6 +28,7 @@ public class TestInjector implements Injector { private final FakeLocationPowerSaveModeHelper mLocationPowerSaveModeHelper; private final FakeScreenInteractiveHelper mScreenInteractiveHelper; private final LocationAttributionHelper mLocationAttributionHelper; + private final FakeEmergencyHelper mEmergencyHelper; private final LocationUsageLogger mLocationUsageLogger; public TestInjector() { @@ -41,6 +42,7 @@ public class TestInjector implements Injector { mLocationPowerSaveModeHelper = new FakeLocationPowerSaveModeHelper(mLocationEventLog); mScreenInteractiveHelper = new FakeScreenInteractiveHelper(); mLocationAttributionHelper = new LocationAttributionHelper(mAppOpsHelper); + mEmergencyHelper = new FakeEmergencyHelper(); mLocationUsageLogger = new LocationUsageLogger(); } @@ -89,6 +91,11 @@ public class TestInjector implements Injector { return mLocationAttributionHelper; } + @Override + public EmergencyHelper getEmergencyHelper() { + return mEmergencyHelper; + } + @Override public LocationUsageLogger getLocationUsageLogger() { return mLocationUsageLogger;