diff --git a/location/java/android/location/GnssCapabilities.java b/location/java/android/location/GnssCapabilities.java index 6a35920e7fa22..badffd171720e 100644 --- a/location/java/android/location/GnssCapabilities.java +++ b/location/java/android/location/GnssCapabilities.java @@ -77,15 +77,14 @@ public final class GnssCapabilities { }) public @interface Capability {} - /** - * @hide - */ + /** @hide */ public static final long INVALID_CAPABILITIES = -1; /** A bitmask of supported GNSS capabilities. */ private final long mGnssCapabilities; - static GnssCapabilities of(long gnssCapabilities) { + /** @hide */ + public static GnssCapabilities of(long gnssCapabilities) { return new GnssCapabilities(gnssCapabilities); } diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index be5838944bd02..3410d8d868524 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -52,6 +52,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.IBatchedLocationCallback; import android.location.IGnssMeasurementsListener; @@ -102,6 +103,7 @@ import com.android.server.location.GeocoderProxy; import com.android.server.location.GeofenceManager; import com.android.server.location.GeofenceProxy; import com.android.server.location.GnssBatchingProvider; +import com.android.server.location.GnssCapabilitiesProvider; import com.android.server.location.GnssLocationProvider; import com.android.server.location.GnssMeasurementCorrectionsProvider; import com.android.server.location.GnssMeasurementsProvider; @@ -249,8 +251,8 @@ public class LocationManagerService extends ILocationManager.Stub { private int[] mCurrentUserProfiles = new int[]{UserHandle.USER_SYSTEM}; private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider; - private GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider; + private GnssCapabilitiesProvider mGnssCapabilitiesProvider; private GnssBatchingProvider mGnssBatchingProvider; @GuardedBy("mLock") @@ -773,6 +775,7 @@ public class LocationManagerService extends ILocationManager.Stub { mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider(); mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider(); mGnssMetricsProvider = gnssProvider.getGnssMetricsProvider(); + mGnssCapabilitiesProvider = gnssProvider.getGnssCapabilitiesProvider(); mGnssStatusProvider = gnssProvider.getGnssStatusProvider(); mNetInitiatedListener = gnssProvider.getNetInitiatedListener(); mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider(); @@ -2970,10 +2973,10 @@ public class LocationManagerService extends ILocationManager.Stub { mContext.enforceCallingPermission( android.Manifest.permission.LOCATION_HARDWARE, "Location Hardware permission not granted to obtain GNSS chipset capabilities."); - if (!hasGnssPermissions(packageName) || mGnssMeasurementCorrectionsProvider == null) { - return -1; + if (!hasGnssPermissions(packageName) || mGnssCapabilitiesProvider == null) { + return GnssCapabilities.INVALID_CAPABILITIES; } - return mGnssMeasurementCorrectionsProvider.getCapabilities(); + return mGnssCapabilitiesProvider.getGnssCapabilities(); } @Override diff --git a/services/core/java/com/android/server/location/GnssCapabilitiesProvider.java b/services/core/java/com/android/server/location/GnssCapabilitiesProvider.java new file mode 100644 index 0000000000000..98085b8e219b4 --- /dev/null +++ b/services/core/java/com/android/server/location/GnssCapabilitiesProvider.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2019 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; + +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); + + // Bit masks for capabilities in {@link android.location.GnssCapabilities}. + private static final long GNSS_CAPABILITY_LOW_POWER_MODE = + 1L << GnssCapabilities.LOW_POWER_MODE; + private static final long GNSS_CAPABILITY_SATELLITE_BLACKLIST = + 1L << GnssCapabilities.SATELLITE_BLACKLIST; + private static final long GNSS_CAPABILITY_GEOFENCING = 1L << GnssCapabilities.GEOFENCING; + private static final long GNSS_CAPABILITY_MEASUREMENTS = 1L << GnssCapabilities.MEASUREMENTS; + private static final long GNSS_CAPABILITY_NAV_MESSAGES = 1L << GnssCapabilities.NAV_MESSAGES; + private static final long GNSS_CAPABILITY_MEASUREMENT_CORRECTIONS = + 1L << GnssCapabilities.MEASUREMENT_CORRECTIONS; + private static final long GNSS_CAPABILITY_MEASUREMENT_CORRECTIONS_LOS_SATS = + 1L << GnssCapabilities.MEASUREMENT_CORRECTIONS_LOS_SATS; + private static final long GNSS_CAPABILITY_MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH = + 1L << GnssCapabilities.MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH; + private static final long GNSS_CAPABILITY_MEASUREMENT_CORRECTIONS_REFLECTING_PLANE = + 1L << GnssCapabilities.MEASUREMENT_CORRECTIONS_REFLECTING_PLANE; + + private static final long GNSS_CAPABILITIES_TOP_HAL = + GNSS_CAPABILITY_LOW_POWER_MODE | GNSS_CAPABILITY_SATELLITE_BLACKLIST + | GNSS_CAPABILITY_GEOFENCING | GNSS_CAPABILITY_MEASUREMENTS + | GNSS_CAPABILITY_NAV_MESSAGES; + + private static final long GNSS_CAPABILITIES_SUB_HAL_MEASUREMENT_CORRECTIONS = + GNSS_CAPABILITY_MEASUREMENT_CORRECTIONS + | GNSS_CAPABILITY_MEASUREMENT_CORRECTIONS_LOS_SATS + | GNSS_CAPABILITY_MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH + | GNSS_CAPABILITY_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,
+ boolean hasGeofencingCapability, boolean hasMeasurementsCapability,
+ boolean hasNavMessagesCapability) {
+ long gnssCapabilities = 0;
+ if (hasCapability(topHalCapabilities,
+ GnssLocationProvider.GPS_CAPABILITY_LOW_POWER_MODE)) {
+ gnssCapabilities |= GNSS_CAPABILITY_LOW_POWER_MODE;
+ }
+ if (hasCapability(topHalCapabilities,
+ GnssLocationProvider.GPS_CAPABILITY_SATELLITE_BLACKLIST)) {
+ gnssCapabilities |= GNSS_CAPABILITY_SATELLITE_BLACKLIST;
+ }
+ if (hasGeofencingCapability) {
+ gnssCapabilities |= GNSS_CAPABILITY_GEOFENCING;
+ }
+ if (hasMeasurementsCapability) {
+ gnssCapabilities |= GNSS_CAPABILITY_MEASUREMENTS;
+ }
+ if (hasNavMessagesCapability) {
+ gnssCapabilities |= GNSS_CAPABILITY_NAV_MESSAGES;
+ }
+
+ 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 = GNSS_CAPABILITY_MEASUREMENT_CORRECTIONS;
+ if (hasCapability(measurementCorrectionsCapabilities,
+ GnssMeasurementCorrectionsProvider.CAPABILITY_LOS_SATS)) {
+ gnssCapabilities |= GNSS_CAPABILITY_MEASUREMENT_CORRECTIONS_LOS_SATS;
+ }
+ if (hasCapability(measurementCorrectionsCapabilities,
+ GnssMeasurementCorrectionsProvider.CAPABILITY_EXCESS_PATH_LENGTH)) {
+ gnssCapabilities |= GNSS_CAPABILITY_MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH;
+ }
+ if (hasCapability(measurementCorrectionsCapabilities,
+ GnssMeasurementCorrectionsProvider.CAPABILITY_REFLECTING_PLANE)) {
+ gnssCapabilities |= GNSS_CAPABILITY_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/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 6066fc31fba98..be34adb1fca42 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -173,8 +173,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
public static final int GPS_CAPABILITY_MEASUREMENTS = 0x0000040;
public static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080;
- private static final int GPS_CAPABILITY_LOW_POWER_MODE = 0x0000100;
- private static final int GPS_CAPABILITY_SATELLITE_BLACKLIST = 0x0000200;
+ static final int GPS_CAPABILITY_LOW_POWER_MODE = 0x0000100;
+ static final int GPS_CAPABILITY_SATELLITE_BLACKLIST = 0x0000200;
// The AGPS SUPL mode
private static final int AGPS_SUPL_MODE_MSA = 0x02;
@@ -338,8 +338,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
// true if we started navigation
private boolean mStarted;
- // capabilities of the GPS engine
- private volatile int mEngineCapabilities;
+ // capabilities reported through the top level IGnssCallback.hal
+ private volatile int mTopHalCapabilities;
// true if XTRA is supported
private boolean mSupportsXtra;
@@ -385,6 +385,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
private final NtpTimeHelper mNtpTimeHelper;
private final GnssBatchingProvider mGnssBatchingProvider;
private final GnssGeofenceProvider mGnssGeofenceProvider;
+ private final GnssCapabilitiesProvider mGnssCapabilitiesProvider;
+
// Available only on GNSS HAL 2.0 implementations and later.
private GnssVisibilityControl mGnssVisibilityControl;
@@ -593,10 +595,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
- mNetworkConnectivityHandler = new GnssNetworkConnectivityHandler(
- context,
- GnssLocationProvider.this::onNetworkAvailable,
- looper);
+ mNetworkConnectivityHandler = new GnssNetworkConnectivityHandler(context,
+ GnssLocationProvider.this::onNetworkAvailable, looper);
// App ops service to keep track of who is accessing the GPS
mAppOps = mContext.getSystemService(AppOpsManager.class);
@@ -614,6 +614,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
// 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();
// Create a GPS net-initiated handler (also needed by handleInitialize)
mNIHandler = new GpsNetInitiatedHandler(context,
mNetInitiatedListener,
@@ -1280,12 +1281,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
}
- public int getGnssCapabilities() {
- return mEngineCapabilities;
- }
-
private boolean hasCapability(int capability) {
- return ((mEngineCapabilities & capability) != 0);
+ return (mTopHalCapabilities & capability) != 0;
}
@NativeEntryPoint
@@ -1493,27 +1490,52 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
@NativeEntryPoint
- private void setEngineCapabilities(final int capabilities, boolean hasSubHalCapabilityFlags) {
- // send to handler thread for fast native return, and in-order handling
+ private void setTopHalCapabilities(int topHalCapabilities, boolean hasSubHalCapabilityFlags) {
+ // The IGnssCallback.hal@2.0 removed sub-HAL capability flags from the Capabilities enum
+ // and instead uses the sub-HAL non-null handle returned from IGnss.hal@2.0 to indicate
+ // support. Therefore, the 'hasSubHalCapabilityFlags' parameter is needed to tell if the
+ // 'capabilities' parameter includes the sub-HAL capability flags or not. Old HALs
+ // which explicitly set the sub-HAL capability bits must continue to work.
mHandler.post(() -> {
- mEngineCapabilities = capabilities;
+ mTopHalCapabilities = topHalCapabilities;
if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
mNtpTimeHelper.enablePeriodicTimeInjection();
requestUtcTime();
}
- mGnssMeasurementsProvider.onCapabilitiesUpdated(capabilities, hasSubHalCapabilityFlags);
- mGnssNavigationMessageProvider.onCapabilitiesUpdated(capabilities,
- hasSubHalCapabilityFlags);
+ boolean hasGeofencingCapability;
+ boolean hasMeasurementsCapability;
+ boolean hasNavMessagesCapability;
+ if (hasSubHalCapabilityFlags) {
+ hasGeofencingCapability = hasCapability(GPS_CAPABILITY_GEOFENCING);
+ hasMeasurementsCapability = hasCapability(GPS_CAPABILITY_MEASUREMENTS);
+ hasNavMessagesCapability = hasCapability(GPS_CAPABILITY_NAV_MESSAGES);
+ } else {
+ hasGeofencingCapability = mGnssGeofenceProvider.isHardwareGeofenceSupported();
+ hasMeasurementsCapability = mGnssMeasurementsProvider.isAvailableInPlatform();
+ hasNavMessagesCapability = mGnssNavigationMessageProvider.isAvailableInPlatform();
+ }
+
+ mGnssMeasurementsProvider.onCapabilitiesUpdated(hasMeasurementsCapability);
+ mGnssNavigationMessageProvider.onCapabilitiesUpdated(hasNavMessagesCapability);
restartRequests();
+
+ mGnssCapabilitiesProvider.setTopHalCapabilities(topHalCapabilities,
+ hasGeofencingCapability, hasMeasurementsCapability, hasNavMessagesCapability);
});
}
@NativeEntryPoint
- private void setMeasurementCorrectionsCapabilities(final int capabilities) {
- mHandler.post(() -> mGnssMeasurementCorrectionsProvider.onCapabilitiesUpdated(
- capabilities));
+ private void setSubHalMeasurementCorrectionsCapabilities(int subHalCapabilities) {
+ mHandler.post(() -> {
+ if (!mGnssMeasurementCorrectionsProvider.onCapabilitiesUpdated(subHalCapabilities)) {
+ return;
+ }
+
+ mGnssCapabilitiesProvider.setSubHalMeasurementCorrectionsCapabilities(
+ subHalCapabilities);
+ });
}
private void restartRequests() {
@@ -1614,6 +1636,13 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
return () -> mGnssMetrics.dumpGnssMetricsAsProtoString();
}
+ /**
+ * @hide
+ */
+ public GnssCapabilitiesProvider getGnssCapabilitiesProvider() {
+ return mGnssCapabilitiesProvider;
+ }
+
@NativeEntryPoint
private void reportLocationBatch(Location[] locationArray) {
List