From d626eb6c7ec8a673b35ef19bf4ae4f455207a1f2 Mon Sep 17 00:00:00 2001 From: Soonil Nagarkar Date: Fri, 3 Apr 2020 14:07:21 -0700 Subject: [PATCH] Pull GNSS callbacks out of GnssLocationProvider Ideally class would register individually for the callbacks they care about. However, currently all callbacks are registered together on a single class. We pull all callbacks out of GnssLocationProvider so that they can be diverted to the proper classes, instead of all going through GnssLocationProvider for no particular reason. Test: manual Change-Id: Ia76d5e51d95adeb51ab1c5d7501628b004703861 --- .../location/gnss/GnssLocationProvider.java | 202 +++--------- .../location/gnss/GnssManagerService.java | 172 +++++++++- .../server/location/gnss/GnssNative.java | 312 ++++++++++++++++++ ...d_server_location_GnssLocationProvider.cpp | 120 ++++--- .../location/gnss/GnssManagerServiceTest.java | 10 +- 5 files changed, 610 insertions(+), 206 deletions(-) create mode 100644 services/core/java/com/android/server/location/gnss/GnssNative.java 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 c97a04df18d42..3cf6dfa43f81e 100644 --- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java @@ -68,7 +68,6 @@ import android.util.Log; import android.util.TimeUtils; import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; import com.android.internal.location.GpsNetInitiatedHandler; import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification; @@ -90,10 +89,6 @@ import com.android.server.location.gnss.NtpTimeHelper.InjectNtpTimeCallback; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -107,15 +102,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements InjectNtpTimeCallback, GnssSatelliteBlacklistCallback { - /** - * 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 { - } - private static final String TAG = "GnssLocationProvider"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @@ -311,9 +297,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private final ExponentialBackOff mPsdsBackOff = new ExponentialBackOff(RETRY_INTERVAL, MAX_RETRY_INTERVAL); - private static boolean sIsInitialized = false; - private static boolean sStaticTestOverride = false; - // True if we are enabled @GuardedBy("mLock") private boolean mGpsEnabled; @@ -400,6 +383,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private final GnssBatchingProvider mGnssBatchingProvider; private final GnssGeofenceProvider mGnssGeofenceProvider; private final GnssCapabilitiesProvider mGnssCapabilitiesProvider; + private final GnssSatelliteBlacklistHelper mGnssSatelliteBlacklistHelper; // Available only on GNSS HAL 2.0 implementations and later. private GnssVisibilityControl mGnssVisibilityControl; @@ -590,29 +574,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } } - @VisibleForTesting - public static void setIsSupportedForTest(boolean override) { - sStaticTestOverride = override; - } - - /** - * Indicates if GNSS location is supported. - */ - public static boolean isSupported() { - if (sStaticTestOverride) { - return true; - } - ensureInitialized(); - return native_is_supported(); - } - - private static synchronized void ensureInitialized() { - if (!sIsInitialized) { - class_init_native(); - } - sIsInitialized = true; - } - private void reloadGpsProperties() { mGnssConfiguration.reloadGpsProperties(); setSuplHostPort(); @@ -632,8 +593,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements AppForegroundHelper appForegroundHelper, LocationUsageLogger logger) { super(FgThread.getExecutor(), CallerIdentity.fromContext(context)); - ensureInitialized(); - mContext = context; mLooper = FgThread.getHandler().getLooper(); @@ -675,8 +634,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements mNetworkConnectivityHandler = new GnssNetworkConnectivityHandler(context, GnssLocationProvider.this::onNetworkAvailable, mLooper, mNIHandler); - sendMessage(INITIALIZE_HANDLER, 0, null); - mGnssStatusListenerHelper = new GnssStatusProvider(userInfoHelper, settingsHelper, appOpsHelper, appForegroundHelper, logger); mGnssMeasurementsProvider = new GnssMeasurementsProvider(userInfoHelper, @@ -689,13 +646,18 @@ public class GnssLocationProvider extends AbstractLocationProvider implements mGnssMetrics = new GnssMetrics(mContext, mBatteryStats); mNtpTimeHelper = new NtpTimeHelper(mContext, mLooper, this); - GnssSatelliteBlacklistHelper gnssSatelliteBlacklistHelper = + mGnssSatelliteBlacklistHelper = new GnssSatelliteBlacklistHelper(mContext, mLooper, this); - mHandler.post(gnssSatelliteBlacklistHelper::updateSatelliteBlacklist); mGnssBatchingProvider = new GnssBatchingProvider(); mGnssGeofenceProvider = new GnssGeofenceProvider(); + setProperties(PROPERTIES); + setAllowed(true); + } + + /** Called when system is ready. */ + public synchronized void onSystemReady() { mContext.registerReceiverAsUser(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -716,8 +678,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } }, UserHandle.USER_ALL); - setProperties(PROPERTIES); - setAllowed(true); + sendMessage(INITIALIZE_HANDLER, 0, null); + mHandler.post(mGnssSatelliteBlacklistHelper::updateSatelliteBlacklist); } /** @@ -1327,8 +1289,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements return (mTopHalCapabilities & capability) != 0; } - @NativeEntryPoint - private void reportLocation(boolean hasLatLong, Location location) { + void reportLocation(boolean hasLatLong, Location location) { sendMessage(REPORT_LOCATION, hasLatLong ? 1 : 0, location); } @@ -1410,8 +1371,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } } - @NativeEntryPoint - private void reportStatus(int status) { + void reportStatus(int status) { if (DEBUG) Log.v(TAG, "reportStatus status: " + status); boolean wasNavigating = mNavigating; @@ -1434,8 +1394,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } } - @NativeEntryPoint - private void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0DbHzs, + void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0DbHzs, float[] elevations, float[] azimuths, float[] carrierFrequencies, float[] basebandCn0DbHzs) { sendMessage(REPORT_SV_STATUS, 0, @@ -1475,13 +1434,11 @@ public class GnssLocationProvider extends AbstractLocationProvider implements mGnssMetrics.logSvStatus(gnssStatus); } - @NativeEntryPoint - private void reportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) { + void reportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) { mNetworkConnectivityHandler.onReportAGpsStatus(agpsType, agpsStatus, suplIpAddr); } - @NativeEntryPoint - private void reportNmea(long timestamp) { + void reportNmea(long timestamp) { if (!mItarSpeedLimitExceeded) { int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length); String nmea = new String(mNmeaBuffer, 0 /* offset */, length); @@ -1489,29 +1446,25 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } } - @NativeEntryPoint - private void reportMeasurementData(GnssMeasurementsEvent event) { + void reportMeasurementData(GnssMeasurementsEvent event) { if (!mItarSpeedLimitExceeded) { // send to handler to allow native to return quickly mHandler.post(() -> mGnssMeasurementsProvider.onMeasurementsAvailable(event)); } } - @NativeEntryPoint - private void reportAntennaInfo(List antennaInfos) { + void reportAntennaInfo(List antennaInfos) { mHandler.post(() -> mGnssAntennaInfoProvider.onGnssAntennaInfoAvailable(antennaInfos)); } - @NativeEntryPoint - private void reportNavigationMessage(GnssNavigationMessage event) { + void reportNavigationMessage(GnssNavigationMessage event) { if (!mItarSpeedLimitExceeded) { // send to handler to allow native to return quickly mHandler.post(() -> mGnssNavigationMessageProvider.onNavigationMessageAvailable(event)); } } - @NativeEntryPoint - private void setTopHalCapabilities(int topHalCapabilities) { + void setTopHalCapabilities(int topHalCapabilities) { mHandler.post(() -> { mTopHalCapabilities = topHalCapabilities; @@ -1526,8 +1479,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements }); } - @NativeEntryPoint - private void setSubHalMeasurementCorrectionsCapabilities(int subHalCapabilities) { + void setSubHalMeasurementCorrectionsCapabilities(int subHalCapabilities) { mHandler.post(() -> { if (!mGnssMeasurementCorrectionsProvider.onCapabilitiesUpdated(subHalCapabilities)) { return; @@ -1552,32 +1504,32 @@ public class GnssLocationProvider extends AbstractLocationProvider implements updateRequirements(); } - @NativeEntryPoint - private void setGnssYearOfHardware(final int yearOfHardware) { + 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; } - @NativeEntryPoint - private void setGnssHardwareModelName(final String modelName) { + 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; } - @NativeEntryPoint - private void reportGnssServiceDied() { + void reportGnssServiceRestarted() { if (DEBUG) Log.d(TAG, "reportGnssServiceDied"); - mHandler.post(() -> { - setupNativeGnssService(/* reinitializeGnssServiceHandle = */ true); - // resend configuration into the restarted HAL service. - reloadGpsProperties(); - if (isGpsEnabled()) { - setGpsEnabled(false); - updateEnabled(); - } - }); + + // 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(); + } } /** @@ -1643,8 +1595,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements return mGnssCapabilitiesProvider; } - @NativeEntryPoint - private void reportLocationBatch(Location[] locationArray) { + void reportLocationBatch(Location[] locationArray) { List locations = new ArrayList<>(Arrays.asList(locationArray)); if (DEBUG) { Log.d(TAG, "Location batch of size " + locationArray.length + " reported"); @@ -1652,8 +1603,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements reportLocation(locations); } - @NativeEntryPoint - private void psdsDownloadRequest() { + void psdsDownloadRequest() { if (DEBUG) Log.d(TAG, "psdsDownloadRequest"); sendMessage(DOWNLOAD_PSDS_DATA, 0, null); } @@ -1680,8 +1630,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } } - @NativeEntryPoint - private void reportGeofenceTransition(int geofenceId, Location location, int transition, + void reportGeofenceTransition(int geofenceId, Location location, int transition, long transitionTimestamp) { mHandler.post(() -> { if (mGeofenceHardwareImpl == null) { @@ -1698,8 +1647,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements }); } - @NativeEntryPoint - private void reportGeofenceStatus(int status, Location location) { + void reportGeofenceStatus(int status, Location location) { mHandler.post(() -> { if (mGeofenceHardwareImpl == null) { mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); @@ -1716,8 +1664,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements }); } - @NativeEntryPoint - private void reportGeofenceAddStatus(int geofenceId, int status) { + void reportGeofenceAddStatus(int geofenceId, int status) { mHandler.post(() -> { if (mGeofenceHardwareImpl == null) { mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); @@ -1726,8 +1673,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements }); } - @NativeEntryPoint - private void reportGeofenceRemoveStatus(int geofenceId, int status) { + void reportGeofenceRemoveStatus(int geofenceId, int status) { mHandler.post(() -> { if (mGeofenceHardwareImpl == null) { mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); @@ -1736,8 +1682,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements }); } - @NativeEntryPoint - private void reportGeofencePauseStatus(int geofenceId, int status) { + void reportGeofencePauseStatus(int geofenceId, int status) { mHandler.post(() -> { if (mGeofenceHardwareImpl == null) { mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); @@ -1746,8 +1691,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements }); } - @NativeEntryPoint - private void reportGeofenceResumeStatus(int geofenceId, int status) { + void reportGeofenceResumeStatus(int geofenceId, int status) { mHandler.post(() -> { if (mGeofenceHardwareImpl == null) { mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); @@ -1797,18 +1741,9 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } /** Reports a NI notification. */ - @NativeEntryPoint - public void reportNiNotification( - int notificationId, - int niType, - int notifyFlags, - int timeout, - int defaultResponse, - String requestorId, - String text, - int requestorIdEncoding, - int textEncoding - ) { + 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"); Log.i(TAG, "notificationId: " + notificationId + ", niType: " + niType @@ -1859,8 +1794,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements * We should be careful about receiving null string from the TelephonyManager, * because sending null String to JNI function would cause a crash. */ - @NativeEntryPoint - private void requestSetID(int flags) { + void requestSetID(int flags) { TelephonyManager phone = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); int type = AGPS_SETID_TYPE_NONE; @@ -1887,8 +1821,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements native_agps_set_id(type, (setId == null) ? "" : setId); } - @NativeEntryPoint - private void requestLocation(boolean independentFromGnss, boolean isUserEmergency) { + void requestLocation(boolean independentFromGnss, boolean isUserEmergency) { if (DEBUG) { Log.d(TAG, "requestLocation. independentFromGnss: " + independentFromGnss + ", isUserEmergency: " @@ -1897,14 +1830,12 @@ public class GnssLocationProvider extends AbstractLocationProvider implements sendMessage(REQUEST_LOCATION, independentFromGnss ? 1 : 0, isUserEmergency); } - @NativeEntryPoint - private void requestUtcTime() { + void requestUtcTime() { if (DEBUG) Log.d(TAG, "utcTimeRequest"); sendMessage(INJECT_NTP_TIME, 0, null); } - @NativeEntryPoint - private void requestRefLocation() { + void requestRefLocation() { TelephonyManager phone = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); final int phoneType = phone.getPhoneType(); @@ -1936,8 +1867,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } // Implements method nfwNotifyCb() in IGnssVisibilityControlCallback.hal. - @NativeEntryPoint - private void reportNfwNotification(String proxyAppPackageName, byte protocolStack, + void reportNfwNotification(String proxyAppPackageName, byte protocolStack, String otherProtocolStackName, byte requestor, String requestorId, byte responseType, boolean inEmergencyMode, boolean isCachedLocation) { if (mGnssVisibilityControl == null) { @@ -1951,7 +1881,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } // Implements method isInEmergencySession() in IGnssVisibilityControlCallback.hal. - @NativeEntryPoint boolean isInEmergencySession() { return mNIHandler.getInEmergency(); } @@ -2020,8 +1949,10 @@ public class GnssLocationProvider extends AbstractLocationProvider implements * registering for events that will be posted to this handler. */ private void handleInitialize() { - // class_init_native() already initializes the GNSS service handle during class loading. - setupNativeGnssService(/* reinitializeGnssServiceHandle = */ false); + // 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()) { mGnssVisibilityControl = new GnssVisibilityControl(mContext, mLooper, mNIHandler); @@ -2155,34 +2086,11 @@ public class GnssLocationProvider extends AbstractLocationProvider implements pw.append(s); } - private void setupNativeGnssService(boolean reinitializeGnssServiceHandle) { - native_init_once(reinitializeGnssServiceHandle); - - /* - * A cycle of native_init() and native_cleanup() is needed so that callbacks are - * registered after bootup even when location is disabled. - * This will allow Emergency SUPL to work even when location is disabled before device - * restart. - */ - boolean isInitialized = native_init(); - if (!isInitialized) { - Log.w(TAG, "Native initialization failed."); - } else { - native_cleanup(); - } - } - // preallocated to avoid memory allocation in reportNmea() private byte[] mNmeaBuffer = new byte[120]; - private static native void class_init_native(); - - private static native boolean native_is_supported(); - private static native boolean native_is_gnss_visibility_control_supported(); - private static native void native_init_once(boolean reinitializeGnssServiceHandle); - private native boolean native_init(); private native void native_cleanup(); 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 d614983e9d10c..9a26a1149b221 100644 --- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java +++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java @@ -22,7 +22,10 @@ import static android.location.util.identity.CallerIdentity.PERMISSION_FINE; import android.Manifest; import android.annotation.Nullable; import android.content.Context; +import android.location.GnssAntennaInfo; import android.location.GnssMeasurementCorrections; +import android.location.GnssMeasurementsEvent; +import android.location.GnssNavigationMessage; import android.location.GnssRequest; import android.location.IBatchedLocationCallback; import android.location.IGnssAntennaInfoListener; @@ -54,15 +57,15 @@ import java.io.PrintWriter; import java.util.List; /** Manages Gnss providers and related Gnss functions for LocationManagerService. */ -public class GnssManagerService { +public class GnssManagerService implements GnssNative.Callbacks { public static final String TAG = "GnssManager"; public static final boolean D = Log.isLoggable(TAG, Log.DEBUG); - private static final String FEATURE_ID = "GnssService"; + private static final String ATTRIBUTION_ID = "GnssService"; public static boolean isGnssSupported() { - return GnssLocationProvider.isSupported(); + return GnssNative.isSupported(); } private final Context mContext; @@ -109,7 +112,9 @@ public class GnssManagerService { GnssLocationProvider gnssLocationProvider) { Preconditions.checkState(isGnssSupported()); - mContext = context.createFeatureContext(FEATURE_ID); + GnssNative.initialize(); + + mContext = context.createAttributionContext(ATTRIBUTION_ID); mSettingsHelper = settingsHelper; mAppOpsHelper = appOpsHelper; mAppForegroundHelper = appForegroundHelper; @@ -133,6 +138,9 @@ public class GnssManagerService { mGnssBatchingProvider = mGnssLocationProvider.getGnssBatchingProvider(); mNetInitiatedListener = mGnssLocationProvider.getNetInitiatedListener(); mGpsGeofenceProxy = mGnssLocationProvider.getGpsGeofenceProxy(); + + // allow gnss access to begin - we must assume that callbacks can start immediately + GnssNative.register(this); } /** Called when system is ready. */ @@ -140,6 +148,8 @@ public class GnssManagerService { mAppOpsHelper.onSystemReady(); mSettingsHelper.onSystemReady(); mAppForegroundHelper.onSystemReady(); + + mGnssLocationProvider.onSystemReady(); } /** Retrieve the GnssLocationProvider. */ @@ -454,4 +464,158 @@ public class GnssManagerService { } } } + + // all native callbacks - to be funneled to various locations as appropriate + + @Override + public void reportLocation(boolean hasLatLong, Location location) { + mGnssLocationProvider.reportLocation(hasLatLong, location); + } + + @Override + public void reportStatus(int status) { + mGnssLocationProvider.reportStatus(status); + } + + @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 reportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) { + mGnssLocationProvider.reportAGpsStatus(agpsType, agpsStatus, suplIpAddr); + } + + @Override + public void reportNmea(long timestamp) { + mGnssLocationProvider.reportNmea(timestamp); + } + + @Override + public void reportMeasurementData(GnssMeasurementsEvent event) { + mGnssLocationProvider.reportMeasurementData(event); + } + + @Override + public void reportAntennaInfo(List antennaInfos) { + mGnssLocationProvider.reportAntennaInfo(antennaInfos); + } + + @Override + public void reportNavigationMessage(GnssNavigationMessage event) { + mGnssLocationProvider.reportNavigationMessage(event); + } + + @Override + public void setTopHalCapabilities(int topHalCapabilities) { + mGnssLocationProvider.setTopHalCapabilities(topHalCapabilities); + } + + @Override + public void setSubHalMeasurementCorrectionsCapabilities(int subHalCapabilities) { + mGnssLocationProvider.setSubHalMeasurementCorrectionsCapabilities(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() { + mGnssLocationProvider.psdsDownloadRequest(); + } + + @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(); + } } diff --git a/services/core/java/com/android/server/location/gnss/GnssNative.java b/services/core/java/com/android/server/location/gnss/GnssNative.java new file mode 100644 index 0000000000000..7c4f47eafacc0 --- /dev/null +++ b/services/core/java/com/android/server/location/gnss/GnssNative.java @@ -0,0 +1,312 @@ +/* + * 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 setTopHalCapabilities(int topHalCapabilities); + void setSubHalMeasurementCorrectionsCapabilities(int subHalCapabilities); + void setGnssYearOfHardware(int yearOfHardware); + void setGnssHardwareModelName(String modelName); + void reportGnssServiceRestarted(); + void reportLocationBatch(Location[] locationArray); + void psdsDownloadRequest(); + 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 setTopHalCapabilities(int topHalCapabilities) { + mCallbacks.setTopHalCapabilities(topHalCapabilities); + } + + @NativeEntryPoint + private void setSubHalMeasurementCorrectionsCapabilities(int subHalCapabilities) { + mCallbacks.setSubHalMeasurementCorrectionsCapabilities(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() { + mCallbacks.psdsDownloadRequest(); + } + + @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/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index e4061b4fc34cb..071cb1b1b099f 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -1905,7 +1905,7 @@ static void android_location_GnssLocationProvider_set_gps_service_handle() { } /* One time initialization at system boot */ -static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, jclass clazz) { +static void android_location_GnssNative_class_init_once(JNIEnv* env, jclass clazz) { // Initialize the top level gnss HAL handle. android_location_GnssLocationProvider_set_gps_service_handle(); @@ -2085,8 +2085,8 @@ static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, } /* Initialization needed at system boot and whenever GNSS service dies. */ -static void android_location_GnssLocationProvider_init_once(JNIEnv* env, jclass clazz, - jboolean reinitializeGnssServiceHandle) { +static void android_location_GnssNative_init_once(JNIEnv* env, jobject obj, + jboolean reinitializeGnssServiceHandle) { /* * Save a pointer to JVM. */ @@ -2331,10 +2331,15 @@ static void android_location_GnssLocationProvider_init_once(JNIEnv* env, jclass gnssVisibilityControlIface = gnssVisibilityControl; } } + + if (mCallbacksObj) { + ALOGE("Callbacks already initialized"); + } else { + mCallbacksObj = env->NewGlobalRef(obj); + } } -static jboolean android_location_GnssLocationProvider_is_supported( - JNIEnv* /* env */, jclass /* clazz */) { +static jboolean android_location_GnssNative_is_supported(JNIEnv* /* env */, jclass /* clazz */) { return (gnssHal != nullptr) ? JNI_TRUE : JNI_FALSE; } @@ -2367,12 +2372,14 @@ 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_GnssLocationProvider_init(JNIEnv* /* env */, jobject /* obj */) { /* * This must be set before calling into the HAL library. */ - if (!mCallbacksObj) - mCallbacksObj = env->NewGlobalRef(obj); + if (!mCallbacksObj) { + ALOGE("No callbacks set during GNSS HAL initialization."); + return JNI_FALSE; + } /* * Fail if the main interface fails to initialize @@ -3581,49 +3588,54 @@ static jboolean android_location_GnssVisibilityControl_enable_nfw_location_acces return checkHidlReturn(result, "IGnssVisibilityControl enableNfwLocationAccess() failed."); } -static const JNINativeMethod sMethods[] = { - /* name, signature, funcPtr */ - {"class_init_native", "()V", reinterpret_cast( - android_location_GnssLocationProvider_class_init_native)}, - {"native_is_supported", "()Z", reinterpret_cast( - android_location_GnssLocationProvider_is_supported)}, - {"native_init_once", "(Z)V", reinterpret_cast( - android_location_GnssLocationProvider_init_once)}, - {"native_init", "()Z", reinterpret_cast(android_location_GnssLocationProvider_init)}, - {"native_cleanup", "()V", reinterpret_cast( - android_location_GnssLocationProvider_cleanup)}, - {"native_set_position_mode", "(IIIIIZ)Z", reinterpret_cast( - android_location_GnssLocationProvider_set_position_mode)}, - {"native_start", "()Z", reinterpret_cast( - android_location_GnssLocationProvider_start)}, - {"native_stop", "()Z", reinterpret_cast( - android_location_GnssLocationProvider_stop)}, - {"native_delete_aiding_data", "(I)V", reinterpret_cast( - android_location_GnssLocationProvider_delete_aiding_data)}, - {"native_read_nmea", "([BI)I", reinterpret_cast( - android_location_GnssLocationProvider_read_nmea)}, - {"native_inject_time", "(JJI)V", reinterpret_cast( - android_location_GnssLocationProvider_inject_time)}, - {"native_inject_best_location", "(IDDDFFFFFFJIJD)V", reinterpret_cast( - android_location_GnssLocationProvider_inject_best_location)}, - {"native_inject_location", "(DDF)V", reinterpret_cast( - android_location_GnssLocationProvider_inject_location)}, - {"native_supports_psds", "()Z", reinterpret_cast( - android_location_GnssLocationProvider_supports_psds)}, - {"native_inject_psds_data", "([BI)V", reinterpret_cast( - android_location_GnssLocationProvider_inject_psds_data)}, - {"native_agps_set_id", "(ILjava/lang/String;)V", reinterpret_cast( - android_location_GnssLocationProvider_agps_set_id)}, - {"native_agps_set_ref_location_cellid", "(IIIII)V", reinterpret_cast( - android_location_GnssLocationProvider_agps_set_reference_location_cellid)}, - {"native_set_agps_server", "(ILjava/lang/String;I)V", reinterpret_cast( - android_location_GnssLocationProvider_set_agps_server)}, - {"native_send_ni_response", "(II)V", reinterpret_cast( - android_location_GnssLocationProvider_send_ni_response)}, - {"native_get_internal_state", "()Ljava/lang/String;", reinterpret_cast( - android_location_GnssLocationProvider_get_internal_state)}, - {"native_is_gnss_visibility_control_supported", "()Z", reinterpret_cast( - android_location_GnssLocationProvider_is_gnss_visibility_control_supported)}, +static const JNINativeMethod sCoreMethods[] = { + /* name, signature, funcPtr */ + {"native_class_init_once", "()V", + reinterpret_cast(android_location_GnssNative_class_init_once)}, + {"native_is_supported", "()Z", + reinterpret_cast(android_location_GnssNative_is_supported)}, + {"native_init_once", "(Z)V", + reinterpret_cast(android_location_GnssNative_init_once)}, +}; + +static const JNINativeMethod sLocationProviderMethods[] = { + /* name, signature, funcPtr */ + {"native_init", "()Z", reinterpret_cast(android_location_GnssLocationProvider_init)}, + {"native_cleanup", "()V", + reinterpret_cast(android_location_GnssLocationProvider_cleanup)}, + {"native_set_position_mode", "(IIIIIZ)Z", + reinterpret_cast(android_location_GnssLocationProvider_set_position_mode)}, + {"native_start", "()Z", + reinterpret_cast(android_location_GnssLocationProvider_start)}, + {"native_stop", "()Z", reinterpret_cast(android_location_GnssLocationProvider_stop)}, + {"native_delete_aiding_data", "(I)V", + reinterpret_cast(android_location_GnssLocationProvider_delete_aiding_data)}, + {"native_read_nmea", "([BI)I", + reinterpret_cast(android_location_GnssLocationProvider_read_nmea)}, + {"native_inject_time", "(JJI)V", + reinterpret_cast(android_location_GnssLocationProvider_inject_time)}, + {"native_inject_best_location", "(IDDDFFFFFFJIJD)V", + reinterpret_cast(android_location_GnssLocationProvider_inject_best_location)}, + {"native_inject_location", "(DDF)V", + reinterpret_cast(android_location_GnssLocationProvider_inject_location)}, + {"native_supports_psds", "()Z", + reinterpret_cast(android_location_GnssLocationProvider_supports_psds)}, + {"native_inject_psds_data", "([BI)V", + reinterpret_cast(android_location_GnssLocationProvider_inject_psds_data)}, + {"native_agps_set_id", "(ILjava/lang/String;)V", + reinterpret_cast(android_location_GnssLocationProvider_agps_set_id)}, + {"native_agps_set_ref_location_cellid", "(IIIII)V", + reinterpret_cast( + android_location_GnssLocationProvider_agps_set_reference_location_cellid)}, + {"native_set_agps_server", "(ILjava/lang/String;I)V", + reinterpret_cast(android_location_GnssLocationProvider_set_agps_server)}, + {"native_send_ni_response", "(II)V", + reinterpret_cast(android_location_GnssLocationProvider_send_ni_response)}, + {"native_get_internal_state", "()Ljava/lang/String;", + reinterpret_cast(android_location_GnssLocationProvider_get_internal_state)}, + {"native_is_gnss_visibility_control_supported", "()Z", + reinterpret_cast( + android_location_GnssLocationProvider_is_gnss_visibility_control_supported)}, }; static const JNINativeMethod sMethodsBatching[] = { @@ -3791,8 +3803,10 @@ int register_android_server_location_GnssLocationProvider(JNIEnv* env) { sConfigurationMethods, NELEM(sConfigurationMethods)); jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssVisibilityControl", sVisibilityControlMethods, NELEM(sVisibilityControlMethods)); - return jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssLocationProvider", - sMethods, NELEM(sMethods)); + jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssLocationProvider", + sLocationProviderMethods, NELEM(sLocationProviderMethods)); + return jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssNative", + sCoreMethods, NELEM(sCoreMethods)); } } /* namespace android */ 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 index e8780c914f194..c4464ec351882 100644 --- a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java @@ -126,6 +126,9 @@ public class GnssManagerServiceTest { @Mock private LocationManagerInternal mLocationManagerInternal; + @Mock + private GnssNative.GnssNativeInitNative mGnssInitNative; + // Context and handler @Mock private Handler mMockHandler; @@ -138,9 +141,12 @@ public class GnssManagerServiceTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); - GnssLocationProvider.setIsSupportedForTest(true); - when(mMockContext.createFeatureContext(anyString())).thenReturn(mMockContext); + when(mGnssInitNative.isSupported()).thenReturn(true); + GnssNative.setInitNativeForTest(mGnssInitNative); + GnssNative.resetCallbacksForTest(); + + when(mMockContext.createAttributionContext(anyString())).thenReturn(mMockContext); when(mMockContext.getSystemServiceName(AppOpsManager.class)).thenReturn( Context.APP_OPS_SERVICE); when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(