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