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