1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.location.gnss; 18 19 import android.Manifest; 20 import android.annotation.Nullable; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.hardware.location.GeofenceHardware; 24 import android.hardware.location.GeofenceHardwareImpl; 25 import android.location.FusedBatchOptions; 26 import android.location.GnssAntennaInfo; 27 import android.location.GnssCapabilities; 28 import android.location.GnssMeasurementCorrections; 29 import android.location.GnssMeasurementRequest; 30 import android.location.IGnssAntennaInfoListener; 31 import android.location.IGnssMeasurementsListener; 32 import android.location.IGnssNavigationMessageListener; 33 import android.location.IGnssNmeaListener; 34 import android.location.IGnssStatusListener; 35 import android.location.IGpsGeofenceHardware; 36 import android.location.Location; 37 import android.location.LocationManager; 38 import android.location.util.identity.CallerIdentity; 39 import android.os.BatteryStats; 40 import android.os.Binder; 41 import android.os.ServiceManager; 42 import android.os.UserHandle; 43 import android.util.IndentingPrintWriter; 44 import android.util.Log; 45 46 import com.android.internal.app.IBatteryStats; 47 import com.android.server.FgThread; 48 import com.android.server.location.gnss.hal.GnssNative; 49 import com.android.server.location.injector.Injector; 50 51 import java.io.FileDescriptor; 52 import java.util.List; 53 54 /** Manages Gnss providers and related Gnss functions for LocationManagerService. */ 55 public class GnssManagerService { 56 57 public static final String TAG = "GnssManager"; 58 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG); 59 60 private static final String ATTRIBUTION_ID = "GnssService"; 61 62 final Context mContext; 63 private final GnssNative mGnssNative; 64 65 private final GnssLocationProvider mGnssLocationProvider; 66 private final GnssStatusProvider mGnssStatusProvider; 67 private final GnssNmeaProvider mGnssNmeaProvider; 68 private final GnssMeasurementsProvider mGnssMeasurementsProvider; 69 private final GnssNavigationMessageProvider mGnssNavigationMessageProvider; 70 private final GnssAntennaInfoProvider mGnssAntennaInfoProvider; 71 private final IGpsGeofenceHardware mGnssGeofenceProxy; 72 73 private final GnssGeofenceHalModule mGeofenceHalModule; 74 private final GnssCapabilitiesHalModule mCapabilitiesHalModule; 75 76 private final GnssMetrics mGnssMetrics; 77 GnssManagerService(Context context, Injector injector, GnssNative gnssNative)78 public GnssManagerService(Context context, Injector injector, GnssNative gnssNative) { 79 mContext = context.createAttributionContext(ATTRIBUTION_ID); 80 mGnssNative = gnssNative; 81 82 mGnssMetrics = new GnssMetrics(mContext, IBatteryStats.Stub.asInterface( 83 ServiceManager.getService(BatteryStats.SERVICE_NAME)), mGnssNative); 84 85 mGnssLocationProvider = new GnssLocationProvider(mContext, mGnssNative, mGnssMetrics); 86 mGnssStatusProvider = new GnssStatusProvider(injector, mGnssNative); 87 mGnssNmeaProvider = new GnssNmeaProvider(injector, mGnssNative); 88 mGnssMeasurementsProvider = new GnssMeasurementsProvider(injector, mGnssNative); 89 mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(injector, mGnssNative); 90 mGnssAntennaInfoProvider = new GnssAntennaInfoProvider(mGnssNative); 91 mGnssGeofenceProxy = new GnssGeofenceProxy(mGnssNative); 92 93 mGeofenceHalModule = new GnssGeofenceHalModule(mGnssNative); 94 mCapabilitiesHalModule = new GnssCapabilitiesHalModule(mGnssNative); 95 96 // allow gnss access to begin - we must assume that callbacks can start immediately 97 mGnssNative.register(); 98 } 99 100 /** Called when system is ready. */ onSystemReady()101 public void onSystemReady() { 102 mGnssLocationProvider.onSystemReady(); 103 } 104 105 /** Retrieve the GnssLocationProvider. */ getGnssLocationProvider()106 public GnssLocationProvider getGnssLocationProvider() { 107 return mGnssLocationProvider; 108 } 109 110 /** 111 * Set whether the GnssLocationProvider is suspended on the device. This method was added to 112 * help support power management use cases on automotive devices. 113 */ setAutomotiveGnssSuspended(boolean suspended)114 public void setAutomotiveGnssSuspended(boolean suspended) { 115 mGnssLocationProvider.setAutomotiveGnssSuspended(suspended); 116 } 117 118 /** 119 * Return whether the GnssLocationProvider is suspended or not. This method was added to 120 * help support power management use cases on automotive devices. 121 */ isAutomotiveGnssSuspended()122 public boolean isAutomotiveGnssSuspended() { 123 return mGnssLocationProvider.isAutomotiveGnssSuspended(); 124 } 125 126 /** Retrieve the IGpsGeofenceHardware. */ getGnssGeofenceProxy()127 public IGpsGeofenceHardware getGnssGeofenceProxy() { 128 return mGnssGeofenceProxy; 129 } 130 131 /** 132 * Get year of GNSS hardware. 133 */ getGnssYearOfHardware()134 public int getGnssYearOfHardware() { 135 return mGnssNative.getHardwareYear(); 136 } 137 138 /** 139 * Get model name of GNSS hardware. 140 */ 141 @Nullable getGnssHardwareModelName()142 public String getGnssHardwareModelName() { 143 return mGnssNative.getHardwareModelName(); 144 } 145 146 /** 147 * Get GNSS hardware capabilities. 148 */ getGnssCapabilities()149 public GnssCapabilities getGnssCapabilities() { 150 return mGnssNative.getCapabilities(); 151 } 152 153 /** 154 * Get GNSS antenna information. 155 */ getGnssAntennaInfos()156 public @Nullable List<GnssAntennaInfo> getGnssAntennaInfos() { 157 return mGnssAntennaInfoProvider.getAntennaInfos(); 158 } 159 160 /** 161 * Get size of GNSS batch (GNSS location results are batched together for power savings). 162 */ getGnssBatchSize()163 public int getGnssBatchSize() { 164 return mGnssLocationProvider.getBatchSize(); 165 } 166 167 /** 168 * Registers listener for GNSS status changes. 169 */ registerGnssStatusCallback(IGnssStatusListener listener, String packageName, @Nullable String attributionTag, String listenerId)170 public void registerGnssStatusCallback(IGnssStatusListener listener, String packageName, 171 @Nullable String attributionTag, String listenerId) { 172 mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null); 173 174 CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag, 175 listenerId); 176 mGnssStatusProvider.addListener(identity, listener); 177 } 178 179 /** 180 * Unregisters listener for GNSS status changes. 181 */ unregisterGnssStatusCallback(IGnssStatusListener listener)182 public void unregisterGnssStatusCallback(IGnssStatusListener listener) { 183 mGnssStatusProvider.removeListener(listener); 184 } 185 186 /** 187 * Registers listener for GNSS NMEA messages. 188 */ registerGnssNmeaCallback(IGnssNmeaListener listener, String packageName, @Nullable String attributionTag, String listenerId)189 public void registerGnssNmeaCallback(IGnssNmeaListener listener, String packageName, 190 @Nullable String attributionTag, String listenerId) { 191 mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null); 192 193 CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag, 194 listenerId); 195 mGnssNmeaProvider.addListener(identity, listener); 196 } 197 198 /** 199 * Unregisters listener for GNSS NMEA messages. 200 */ unregisterGnssNmeaCallback(IGnssNmeaListener listener)201 public void unregisterGnssNmeaCallback(IGnssNmeaListener listener) { 202 mGnssNmeaProvider.removeListener(listener); 203 } 204 205 /** 206 * Adds a GNSS measurements listener. 207 */ addGnssMeasurementsListener(GnssMeasurementRequest request, IGnssMeasurementsListener listener, String packageName, @Nullable String attributionTag, String listenerId)208 public void addGnssMeasurementsListener(GnssMeasurementRequest request, 209 IGnssMeasurementsListener listener, String packageName, 210 @Nullable String attributionTag, String listenerId) { 211 mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null); 212 if (request.isCorrelationVectorOutputsEnabled()) { 213 mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null); 214 } 215 CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag, 216 listenerId); 217 mGnssMeasurementsProvider.addListener(request, identity, listener); 218 } 219 220 /** 221 * Injects GNSS measurement corrections. 222 */ injectGnssMeasurementCorrections(GnssMeasurementCorrections corrections)223 public void injectGnssMeasurementCorrections(GnssMeasurementCorrections corrections) { 224 mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null); 225 mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null); 226 227 if (!mGnssNative.injectMeasurementCorrections(corrections)) { 228 Log.w(TAG, "failed to inject GNSS measurement corrections"); 229 } 230 } 231 232 /** 233 * Removes a GNSS measurements listener. 234 */ removeGnssMeasurementsListener(IGnssMeasurementsListener listener)235 public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) { 236 mGnssMeasurementsProvider.removeListener(listener); 237 } 238 239 /** 240 * Adds a GNSS navigation message listener. 241 */ addGnssNavigationMessageListener(IGnssNavigationMessageListener listener, String packageName, @Nullable String attributionTag, String listenerId)242 public void addGnssNavigationMessageListener(IGnssNavigationMessageListener listener, 243 String packageName, @Nullable String attributionTag, String listenerId) { 244 mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null); 245 246 CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag, 247 listenerId); 248 mGnssNavigationMessageProvider.addListener(identity, listener); 249 } 250 251 /** 252 * Removes a GNSS navigation message listener. 253 */ removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener)254 public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) { 255 mGnssNavigationMessageProvider.removeListener(listener); 256 } 257 258 /** 259 * Adds a GNSS antenna info listener. 260 */ addGnssAntennaInfoListener(IGnssAntennaInfoListener listener, String packageName, @Nullable String attributionTag, String listenerId)261 public void addGnssAntennaInfoListener(IGnssAntennaInfoListener listener, String packageName, 262 @Nullable String attributionTag, String listenerId) { 263 264 CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag, 265 listenerId); 266 mGnssAntennaInfoProvider.addListener(identity, listener); 267 } 268 269 /** 270 * Removes a GNSS antenna info listener. 271 */ removeGnssAntennaInfoListener(IGnssAntennaInfoListener listener)272 public void removeGnssAntennaInfoListener(IGnssAntennaInfoListener listener) { 273 mGnssAntennaInfoProvider.removeListener(listener); 274 } 275 276 /** 277 * Dump info for debugging. 278 */ dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args)279 public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) { 280 if (args.length > 0 && args[0].equals("--gnssmetrics")) { 281 ipw.append(mGnssMetrics.dumpGnssMetricsAsProtoString()); 282 return; 283 } 284 285 ipw.println("Capabilities: " + mGnssNative.getCapabilities()); 286 ipw.println("GNSS Hardware Model Name: " + getGnssHardwareModelName()); 287 288 if (mGnssStatusProvider.isSupported()) { 289 ipw.println("Status Provider:"); 290 ipw.increaseIndent(); 291 mGnssStatusProvider.dump(fd, ipw, args); 292 ipw.decreaseIndent(); 293 } 294 295 if (mGnssMeasurementsProvider.isSupported()) { 296 ipw.println("Measurements Provider:"); 297 ipw.increaseIndent(); 298 mGnssMeasurementsProvider.dump(fd, ipw, args); 299 ipw.decreaseIndent(); 300 } 301 302 if (mGnssNavigationMessageProvider.isSupported()) { 303 ipw.println("Navigation Message Provider:"); 304 ipw.increaseIndent(); 305 mGnssNavigationMessageProvider.dump(fd, ipw, args); 306 ipw.decreaseIndent(); 307 } 308 309 if (mGnssAntennaInfoProvider.isSupported()) { 310 ipw.println("Antenna Info Provider:"); 311 ipw.increaseIndent(); 312 ipw.println("Antenna Infos: " + mGnssAntennaInfoProvider.getAntennaInfos()); 313 mGnssAntennaInfoProvider.dump(fd, ipw, args); 314 ipw.decreaseIndent(); 315 } 316 317 GnssPowerStats powerStats = mGnssNative.getLastKnownPowerStats(); 318 if (powerStats != null) { 319 ipw.println("Last Known Power Stats:"); 320 ipw.increaseIndent(); 321 powerStats.dump(fd, ipw, args, mGnssNative.getCapabilities()); 322 ipw.decreaseIndent(); 323 } 324 } 325 326 private class GnssCapabilitiesHalModule implements GnssNative.BaseCallbacks { 327 GnssCapabilitiesHalModule(GnssNative gnssNative)328 GnssCapabilitiesHalModule(GnssNative gnssNative) { 329 gnssNative.addBaseCallbacks(this); 330 } 331 332 @Override onHalRestarted()333 public void onHalRestarted() {} 334 335 @Override onCapabilitiesChanged(GnssCapabilities oldCapabilities, GnssCapabilities newCapabilities)336 public void onCapabilitiesChanged(GnssCapabilities oldCapabilities, 337 GnssCapabilities newCapabilities) { 338 final long ident = Binder.clearCallingIdentity(); 339 try { 340 Intent intent = new Intent(LocationManager.ACTION_GNSS_CAPABILITIES_CHANGED) 341 .putExtra(LocationManager.EXTRA_GNSS_CAPABILITIES, newCapabilities) 342 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY) 343 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 344 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 345 } finally { 346 Binder.restoreCallingIdentity(ident); 347 } 348 } 349 } 350 351 private class GnssGeofenceHalModule implements GnssNative.GeofenceCallbacks { 352 353 private GeofenceHardwareImpl mGeofenceHardwareImpl; 354 GnssGeofenceHalModule(GnssNative gnssNative)355 GnssGeofenceHalModule(GnssNative gnssNative) { 356 gnssNative.setGeofenceCallbacks(this); 357 } 358 getGeofenceHardware()359 private synchronized GeofenceHardwareImpl getGeofenceHardware() { 360 if (mGeofenceHardwareImpl == null) { 361 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 362 } 363 return mGeofenceHardwareImpl; 364 } 365 366 @Override onReportGeofenceTransition(int geofenceId, Location location, @GeofenceTransition int transition, long timestamp)367 public void onReportGeofenceTransition(int geofenceId, Location location, 368 @GeofenceTransition int transition, long timestamp) { 369 FgThread.getHandler().post(() -> getGeofenceHardware().reportGeofenceTransition( 370 geofenceId, location, transition, timestamp, 371 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, 372 FusedBatchOptions.SourceTechnologies.GNSS)); 373 } 374 375 @Override onReportGeofenceStatus(@eofenceAvailability int status, Location location)376 public void onReportGeofenceStatus(@GeofenceAvailability int status, Location location) { 377 FgThread.getHandler().post(() -> { 378 int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE; 379 if (status == GEOFENCE_AVAILABILITY_AVAILABLE) { 380 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE; 381 } 382 getGeofenceHardware().reportGeofenceMonitorStatus( 383 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, 384 monitorStatus, 385 location, 386 FusedBatchOptions.SourceTechnologies.GNSS); 387 }); 388 } 389 390 @Override onReportGeofenceAddStatus(int geofenceId, @GeofenceStatus int status)391 public void onReportGeofenceAddStatus(int geofenceId, @GeofenceStatus int status) { 392 FgThread.getHandler().post(() -> getGeofenceHardware().reportGeofenceAddStatus( 393 geofenceId, translateGeofenceStatus(status))); 394 } 395 396 @Override onReportGeofenceRemoveStatus(int geofenceId, @GeofenceStatus int status)397 public void onReportGeofenceRemoveStatus(int geofenceId, @GeofenceStatus int status) { 398 FgThread.getHandler().post(() -> getGeofenceHardware().reportGeofenceRemoveStatus( 399 geofenceId, translateGeofenceStatus(status))); 400 } 401 402 @Override onReportGeofencePauseStatus(int geofenceId, @GeofenceStatus int status)403 public void onReportGeofencePauseStatus(int geofenceId, @GeofenceStatus int status) { 404 FgThread.getHandler().post(() -> getGeofenceHardware().reportGeofencePauseStatus( 405 geofenceId, translateGeofenceStatus(status))); 406 } 407 408 @Override onReportGeofenceResumeStatus(int geofenceId, @GeofenceStatus int status)409 public void onReportGeofenceResumeStatus(int geofenceId, @GeofenceStatus int status) { 410 FgThread.getHandler().post(() -> getGeofenceHardware().reportGeofenceResumeStatus( 411 geofenceId, translateGeofenceStatus(status))); 412 } 413 translateGeofenceStatus(@eofenceStatus int status)414 private int translateGeofenceStatus(@GeofenceStatus int status) { 415 switch (status) { 416 case GEOFENCE_STATUS_OPERATION_SUCCESS: 417 return GeofenceHardware.GEOFENCE_SUCCESS; 418 case GEOFENCE_STATUS_ERROR_GENERIC: 419 return GeofenceHardware.GEOFENCE_FAILURE; 420 case GEOFENCE_STATUS_ERROR_ID_EXISTS: 421 return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS; 422 case GEOFENCE_STATUS_ERROR_INVALID_TRANSITION: 423 return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION; 424 case GEOFENCE_STATUS_ERROR_TOO_MANY_GEOFENCES: 425 return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES; 426 case GEOFENCE_STATUS_ERROR_ID_UNKNOWN: 427 return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN; 428 default: 429 return -1; 430 } 431 } 432 } 433 } 434