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