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
This commit is contained in:
Soonil Nagarkar
2020-04-03 14:07:21 -07:00
parent 49e5dd4511
commit d626eb6c7e
5 changed files with 610 additions and 206 deletions

View File

@@ -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<GnssAntennaInfo> antennaInfos) {
void reportAntennaInfo(List<GnssAntennaInfo> 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<Location> 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();

View File

@@ -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<GnssAntennaInfo> 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();
}
}

View File

@@ -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<GnssAntennaInfo> 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<GnssAntennaInfo> 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);
}

View File

@@ -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<void *>(
android_location_GnssLocationProvider_class_init_native)},
{"native_is_supported", "()Z", reinterpret_cast<void *>(
android_location_GnssLocationProvider_is_supported)},
{"native_init_once", "(Z)V", reinterpret_cast<void *>(
android_location_GnssLocationProvider_init_once)},
{"native_init", "()Z", reinterpret_cast<void *>(android_location_GnssLocationProvider_init)},
{"native_cleanup", "()V", reinterpret_cast<void *>(
android_location_GnssLocationProvider_cleanup)},
{"native_set_position_mode", "(IIIIIZ)Z", reinterpret_cast<void *>(
android_location_GnssLocationProvider_set_position_mode)},
{"native_start", "()Z", reinterpret_cast<void *>(
android_location_GnssLocationProvider_start)},
{"native_stop", "()Z", reinterpret_cast<void *>(
android_location_GnssLocationProvider_stop)},
{"native_delete_aiding_data", "(I)V", reinterpret_cast<void *>(
android_location_GnssLocationProvider_delete_aiding_data)},
{"native_read_nmea", "([BI)I", reinterpret_cast<void *>(
android_location_GnssLocationProvider_read_nmea)},
{"native_inject_time", "(JJI)V", reinterpret_cast<void *>(
android_location_GnssLocationProvider_inject_time)},
{"native_inject_best_location", "(IDDDFFFFFFJIJD)V", reinterpret_cast<void *>(
android_location_GnssLocationProvider_inject_best_location)},
{"native_inject_location", "(DDF)V", reinterpret_cast<void *>(
android_location_GnssLocationProvider_inject_location)},
{"native_supports_psds", "()Z", reinterpret_cast<void *>(
android_location_GnssLocationProvider_supports_psds)},
{"native_inject_psds_data", "([BI)V", reinterpret_cast<void *>(
android_location_GnssLocationProvider_inject_psds_data)},
{"native_agps_set_id", "(ILjava/lang/String;)V", reinterpret_cast<void *>(
android_location_GnssLocationProvider_agps_set_id)},
{"native_agps_set_ref_location_cellid", "(IIIII)V", reinterpret_cast<void *>(
android_location_GnssLocationProvider_agps_set_reference_location_cellid)},
{"native_set_agps_server", "(ILjava/lang/String;I)V", reinterpret_cast<void *>(
android_location_GnssLocationProvider_set_agps_server)},
{"native_send_ni_response", "(II)V", reinterpret_cast<void *>(
android_location_GnssLocationProvider_send_ni_response)},
{"native_get_internal_state", "()Ljava/lang/String;", reinterpret_cast<void *>(
android_location_GnssLocationProvider_get_internal_state)},
{"native_is_gnss_visibility_control_supported", "()Z", reinterpret_cast<void *>(
android_location_GnssLocationProvider_is_gnss_visibility_control_supported)},
static const JNINativeMethod sCoreMethods[] = {
/* name, signature, funcPtr */
{"native_class_init_once", "()V",
reinterpret_cast<void*>(android_location_GnssNative_class_init_once)},
{"native_is_supported", "()Z",
reinterpret_cast<void*>(android_location_GnssNative_is_supported)},
{"native_init_once", "(Z)V",
reinterpret_cast<void*>(android_location_GnssNative_init_once)},
};
static const JNINativeMethod sLocationProviderMethods[] = {
/* name, signature, funcPtr */
{"native_init", "()Z", reinterpret_cast<void*>(android_location_GnssLocationProvider_init)},
{"native_cleanup", "()V",
reinterpret_cast<void*>(android_location_GnssLocationProvider_cleanup)},
{"native_set_position_mode", "(IIIIIZ)Z",
reinterpret_cast<void*>(android_location_GnssLocationProvider_set_position_mode)},
{"native_start", "()Z",
reinterpret_cast<void*>(android_location_GnssLocationProvider_start)},
{"native_stop", "()Z", reinterpret_cast<void*>(android_location_GnssLocationProvider_stop)},
{"native_delete_aiding_data", "(I)V",
reinterpret_cast<void*>(android_location_GnssLocationProvider_delete_aiding_data)},
{"native_read_nmea", "([BI)I",
reinterpret_cast<void*>(android_location_GnssLocationProvider_read_nmea)},
{"native_inject_time", "(JJI)V",
reinterpret_cast<void*>(android_location_GnssLocationProvider_inject_time)},
{"native_inject_best_location", "(IDDDFFFFFFJIJD)V",
reinterpret_cast<void*>(android_location_GnssLocationProvider_inject_best_location)},
{"native_inject_location", "(DDF)V",
reinterpret_cast<void*>(android_location_GnssLocationProvider_inject_location)},
{"native_supports_psds", "()Z",
reinterpret_cast<void*>(android_location_GnssLocationProvider_supports_psds)},
{"native_inject_psds_data", "([BI)V",
reinterpret_cast<void*>(android_location_GnssLocationProvider_inject_psds_data)},
{"native_agps_set_id", "(ILjava/lang/String;)V",
reinterpret_cast<void*>(android_location_GnssLocationProvider_agps_set_id)},
{"native_agps_set_ref_location_cellid", "(IIIII)V",
reinterpret_cast<void*>(
android_location_GnssLocationProvider_agps_set_reference_location_cellid)},
{"native_set_agps_server", "(ILjava/lang/String;I)V",
reinterpret_cast<void*>(android_location_GnssLocationProvider_set_agps_server)},
{"native_send_ni_response", "(II)V",
reinterpret_cast<void*>(android_location_GnssLocationProvider_send_ni_response)},
{"native_get_internal_state", "()Ljava/lang/String;",
reinterpret_cast<void*>(android_location_GnssLocationProvider_get_internal_state)},
{"native_is_gnss_visibility_control_supported", "()Z",
reinterpret_cast<void*>(
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 */

View File

@@ -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(