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