• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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