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