• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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.location.provider;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.content.Context;
22 import android.location.ILocationManager;
23 import android.location.Location;
24 import android.location.LocationManager;
25 import android.location.LocationProvider;
26 import android.location.provider.ILocationProvider;
27 import android.location.provider.ILocationProviderManager;
28 import android.location.provider.ProviderProperties;
29 import android.location.provider.ProviderRequest;
30 import android.os.Build.VERSION_CODES;
31 import android.os.Bundle;
32 import android.os.IBinder;
33 import android.os.RemoteException;
34 import android.os.ServiceManager;
35 import android.os.WorkSource;
36 import android.util.Log;
37 
38 import androidx.annotation.RequiresApi;
39 
40 import java.io.FileDescriptor;
41 import java.io.PrintWriter;
42 import java.util.ArrayList;
43 import java.util.List;
44 
45 /**
46  * Base class for location providers implemented as unbundled services.
47  *
48  * <p>The network location provider must export a service with action
49  * "com.android.location.service.v2.NetworkLocationProvider"
50  * and a valid minor version in a meta-data field on the service, and
51  * then return the result of {@link #getBinder()} on service binding.
52  *
53  * <p>The fused location provider must export a service with action
54  * "com.android.location.service.FusedLocationProvider"
55  * and a valid minor version in a meta-data field on the service, and
56  * then return the result of {@link #getBinder()} on service binding.
57  *
58  * <p>IMPORTANT: This class is effectively a public API for unbundled
59  * applications, and must remain API stable. See README.txt in the root
60  * of this package for more information.
61  *
62  * @deprecated This class is not part of the standard API surface - use
63  * {@link android.location.provider.LocationProviderBase} instead.
64  */
65 @Deprecated
66 public abstract class LocationProviderBase {
67 
68     /**
69      * Callback to be invoked when a flush operation is complete and all flushed locations have been
70      * reported.
71      */
72     protected interface OnFlushCompleteCallback {
73 
74         /**
75          * Should be invoked once the flush is complete.
76          */
onFlushComplete()77         void onFlushComplete();
78     }
79 
80     /**
81      * Bundle key for a version of the location containing no GPS data.
82      * Allows location providers to flag locations as being safe to
83      * feed to LocationFudger.
84      *
85      * @deprecated Do not use from Android R onwards.
86      */
87     @Deprecated
88     public static final String EXTRA_NO_GPS_LOCATION = Location.EXTRA_NO_GPS_LOCATION;
89 
90     /**
91      * Name of the Fused location provider.
92      *
93      * <p>This provider combines inputs for all possible location sources
94      * to provide the best possible Location fix.
95      */
96     public static final String FUSED_PROVIDER = LocationManager.FUSED_PROVIDER;
97 
98     final String mTag;
99     @Nullable final String mAttributionTag;
100     final IBinder mBinder;
101 
102     /**
103      * This field may be removed in the future, do not rely on it.
104      *
105      * @deprecated Do not use this field! Use LocationManager APIs instead. If you use this field
106      * you may be broken in the future.
107      * @hide
108      */
109     @Deprecated
110     protected final ILocationManager mLocationManager;
111 
112     // write locked on mBinder, read lock is optional depending on atomicity requirements
113     @Nullable volatile ILocationProviderManager mManager;
114     volatile ProviderProperties mProperties;
115     volatile boolean mAllowed;
116 
117     /**
118      * @deprecated Prefer
119      * {@link #LocationProviderBase(Context, String, ProviderPropertiesUnbundled)}.
120      */
121     @Deprecated
LocationProviderBase(String tag, ProviderPropertiesUnbundled properties)122     public LocationProviderBase(String tag, ProviderPropertiesUnbundled properties) {
123         this(null, tag, properties);
124     }
125 
126     /**
127      * This constructor associates the feature id of the given context with this location provider.
128      * The location service may afford special privileges to incoming calls identified as belonging
129      * to this location provider.
130      */
131     @RequiresApi(VERSION_CODES.R)
LocationProviderBase(Context context, String tag, ProviderPropertiesUnbundled properties)132     public LocationProviderBase(Context context, String tag,
133             ProviderPropertiesUnbundled properties) {
134         mTag = tag;
135         mAttributionTag = context != null ? context.getAttributionTag() : null;
136         mBinder = new Service();
137 
138         mLocationManager = ILocationManager.Stub.asInterface(
139                 ServiceManager.getService(Context.LOCATION_SERVICE));
140 
141         mManager = null;
142         mProperties = properties.getProviderProperties();
143         mAllowed = true;
144     }
145 
getBinder()146     public IBinder getBinder() {
147         return mBinder;
148     }
149 
150     /**
151      * @deprecated Use {@link #setAllowed(boolean)} instead.
152      */
153     @Deprecated
154     @RequiresApi(VERSION_CODES.Q)
setEnabled(boolean enabled)155     public void setEnabled(boolean enabled) {
156         setAllowed(enabled);
157     }
158 
159     /**
160      * Sets whether this provider is currently allowed or not. Note that this is specific to the
161      * provider only, and is not related to global location settings. This is a hint to the Location
162      * Manager that this provider will generally be unable to fulfill incoming requests. This
163      * provider may still receive callbacks to onSetRequest while not allowed, and must decide
164      * whether to attempt to satisfy those requests or not.
165      *
166      * <p>Some guidelines: providers should set their own allowed/disallowed status based only on
167      * state "owned" by that provider. For instance, providers should not take into account the
168      * state of the location master setting when setting themselves allowed or disallowed, as this
169      * state is not owned by a particular provider. If a provider requires some additional user
170      * consent that is particular to the provider, this should be use to set the allowed/disallowed
171      * state. If the provider proxies to another provider, the child provider's allowed/disallowed
172      * state should be taken into account in the parent's allowed state. For most providers, it is
173      * expected that they will be always allowed.
174      */
175     @RequiresApi(VERSION_CODES.R)
setAllowed(boolean allowed)176     public void setAllowed(boolean allowed) {
177         synchronized (mBinder) {
178             if (mAllowed == allowed) {
179                 return;
180             }
181 
182             mAllowed = allowed;
183         }
184 
185         ILocationProviderManager manager = mManager;
186         if (manager != null) {
187             try {
188                 manager.onSetAllowed(mAllowed);
189             } catch (RemoteException e) {
190                 throw e.rethrowFromSystemServer();
191             } catch (RuntimeException e) {
192                 Log.w(mTag, e);
193             }
194         }
195     }
196 
197     /**
198      * Sets the provider properties that may be queried by clients. Generally speaking, providers
199      * should try to avoid changing their properties after construction.
200      */
201     @RequiresApi(VERSION_CODES.Q)
setProperties(ProviderPropertiesUnbundled properties)202     public void setProperties(ProviderPropertiesUnbundled properties) {
203         synchronized (mBinder) {
204             mProperties = properties.getProviderProperties();
205         }
206 
207         ILocationProviderManager manager = mManager;
208         if (manager != null) {
209             try {
210                 manager.onSetProperties(mProperties);
211             } catch (RemoteException e) {
212                 throw e.rethrowFromSystemServer();
213             } catch (RuntimeException e) {
214                 Log.w(mTag, e);
215             }
216         }
217     }
218 
219     /**
220      * Sets a list of additional packages that should be considered as part of this location
221      * provider for the purposes of generating locations. This should generally only be used when
222      * another package may issue location requests on behalf of this package in the course of
223      * providing location. This will inform location services to treat the other packages as
224      * location providers as well.
225      *
226      * @deprecated On Android R and above this has no effect.
227      */
228     @Deprecated
229     @RequiresApi(VERSION_CODES.Q)
setAdditionalProviderPackages(List<String> packageNames)230     public void setAdditionalProviderPackages(List<String> packageNames) {}
231 
232     /**
233      * @deprecated Use {@link #isAllowed()} instead.
234      */
235     @Deprecated
236     @RequiresApi(VERSION_CODES.Q)
isEnabled()237     public boolean isEnabled() {
238         return isAllowed();
239     }
240 
241     /**
242      * Returns true if this provider is allowed. Providers start as allowed on construction.
243      */
244     @RequiresApi(VERSION_CODES.R)
isAllowed()245     public boolean isAllowed() {
246         return mAllowed;
247     }
248 
249     /**
250      * Reports a new location from this provider.
251      */
reportLocation(@onNull Location location)252     public void reportLocation(@NonNull Location location) {
253         ILocationProviderManager manager = mManager;
254         if (manager != null) {
255             try {
256                 manager.onReportLocation(stripExtras(location));
257             } catch (RemoteException e) {
258                 throw e.rethrowFromSystemServer();
259             } catch (RuntimeException e) {
260                 Log.w(mTag, e);
261             }
262         }
263     }
264 
265     /**
266      * Reports a new batch of locations from this provider. Locations must be ordered in the list
267      * from earliest first to latest last.
268      */
reportLocations(@onNull List<Location> locations)269     public void reportLocations(@NonNull List<Location> locations) {
270         ILocationProviderManager manager = mManager;
271         if (manager != null) {
272             try {
273                 manager.onReportLocations(stripExtras(locations));
274             } catch (RemoteException e) {
275                 throw e.rethrowFromSystemServer();
276             } catch (RuntimeException e) {
277                 Log.w(mTag, e);
278             }
279         }
280     }
281 
onInit()282     protected void onInit() {
283         // call once so that providers designed for APIs pre-Q are not broken
284         onEnable();
285     }
286 
287     /**
288      * @deprecated This callback will be invoked once when the provider is created to maintain
289      * backwards compatibility with providers not designed for Android Q and above. This method
290      * should only be implemented in location providers that need to support SDKs below Android Q.
291      * Even in this case, it is usually unnecessary to implement this callback with the correct
292      * design. This method may be removed in the future.
293      */
294     @Deprecated
onEnable()295     protected void onEnable() {}
296 
297     /**
298      * @deprecated This callback will be never be invoked on Android Q and above. This method should
299      * only be implemented in location providers that need to support SDKs below Android Q. Even in
300      * this case, it is usually unnecessary to implement this callback with the correct design. This
301      * method may be removed in the future.
302      */
303     @Deprecated
onDisable()304     protected void onDisable() {}
305 
306     /**
307      * Set the {@link ProviderRequest} requirements for this provider. Each call to this method
308      * overrides all previous requests. This method might trigger the provider to start returning
309      * locations, or to stop returning locations, depending on the parameters in the request.
310      */
onSetRequest(ProviderRequestUnbundled request, WorkSource source)311     protected abstract void onSetRequest(ProviderRequestUnbundled request, WorkSource source);
312 
313     /**
314      * Requests a flush of any pending batched locations. The callback must always be invoked once
315      * per invocation, and should be invoked after {@link #reportLocation(Location)} or
316      * {@link #reportLocations(List)} has been invoked with any flushed locations. The callback may
317      * be invoked immediately if no locations are flushed.
318      */
onFlush(OnFlushCompleteCallback callback)319     protected void onFlush(OnFlushCompleteCallback callback) {
320         callback.onFlushComplete();
321     }
322 
323     /**
324      * @deprecated This callback will never be invoked on Android Q and above. This method may be
325      * removed in the future. Prefer to dump provider state via the containing service instead.
326      */
327     @Deprecated
onDump(FileDescriptor fd, PrintWriter pw, String[] args)328     protected void onDump(FileDescriptor fd, PrintWriter pw, String[] args) {}
329 
330     /**
331      * This method will no longer be invoked.
332      *
333      * @deprecated This callback will be never be invoked on Android Q and above. This method should
334      * only be implemented in location providers that need to support SDKs below Android Q. This
335      * method may be removed in the future.
336      */
337     @Deprecated
onGetStatus(Bundle extras)338     protected int onGetStatus(Bundle extras) {
339         return LocationProvider.AVAILABLE;
340     }
341 
342     /**
343      * This method will no longer be invoked.
344      *
345      * @deprecated This callback will be never be invoked on Android Q and above. This method should
346      * only be implemented in location providers that need to support SDKs below Android Q. This
347      * method may be removed in the future.
348      */
349     @Deprecated
onGetStatusUpdateTime()350     protected long onGetStatusUpdateTime() {
351         return 0;
352     }
353 
354     /**
355      * Implements location provider specific custom commands. The return value will be ignored on
356      * Android Q and above.
357      */
onSendExtraCommand(@ullable String command, @Nullable Bundle extras)358     protected boolean onSendExtraCommand(@Nullable String command, @Nullable Bundle extras) {
359         return false;
360     }
361 
362     private final class Service extends ILocationProvider.Stub {
363 
Service()364         Service() {
365         }
366 
367         @Override
setLocationProviderManager(ILocationProviderManager manager)368         public void setLocationProviderManager(ILocationProviderManager manager) {
369             synchronized (mBinder) {
370                 try {
371                     manager.onInitialize(mAllowed, mProperties, mAttributionTag);
372                 } catch (RemoteException e) {
373                     throw e.rethrowFromSystemServer();
374                 } catch (RuntimeException e) {
375                     Log.w(mTag, e);
376                 }
377 
378                 mManager = manager;
379             }
380 
381             onInit();
382         }
383 
384         @Override
setRequest(ProviderRequest request)385         public void setRequest(ProviderRequest request) {
386             onSetRequest(new ProviderRequestUnbundled(request), request.getWorkSource());
387         }
388 
389         @Override
flush()390         public void flush() {
391             onFlush(this::onFlushComplete);
392         }
393 
onFlushComplete()394         private void onFlushComplete() {
395             ILocationProviderManager manager = mManager;
396             if (manager != null) {
397                 try {
398                     manager.onFlushComplete();
399                 } catch (RemoteException e) {
400                     throw e.rethrowFromSystemServer();
401                 } catch (RuntimeException e) {
402                     Log.w(mTag, e);
403                 }
404             }
405         }
406 
407         @Override
sendExtraCommand(String command, Bundle extras)408         public void sendExtraCommand(String command, Bundle extras) {
409             onSendExtraCommand(command, extras);
410         }
411     }
412 
stripExtras(Location location)413     private static Location stripExtras(Location location) {
414         Bundle extras = location.getExtras();
415         if (extras != null && (extras.containsKey(EXTRA_NO_GPS_LOCATION)
416                 || extras.containsKey("indoorProbability")
417                 || extras.containsKey("coarseLocation"))) {
418             location = new Location(location);
419             extras = location.getExtras();
420             extras.remove(EXTRA_NO_GPS_LOCATION);
421             extras.remove("indoorProbability");
422             extras.remove("coarseLocation");
423             if (extras.isEmpty()) {
424                 location.setExtras(null);
425             }
426         }
427         return location;
428     }
429 
stripExtras(List<Location> locations)430     private static List<Location> stripExtras(List<Location> locations) {
431         List<Location> mapped = locations;
432         final int size = locations.size();
433         int i = 0;
434         for (Location location : locations) {
435             Location newLocation = stripExtras(location);
436             if (mapped != locations) {
437                 mapped.add(newLocation);
438             } else if (newLocation != location) {
439                 mapped = new ArrayList<>(size);
440                 int j = 0;
441                 for (Location copiedLocation : locations) {
442                     if (j >= i) {
443                         break;
444                     }
445                     mapped.add(copiedLocation);
446                     j++;
447                 }
448                 mapped.add(newLocation);
449             }
450             i++;
451         }
452 
453         return mapped;
454     }
455 }
456