blob: bae2d223045b33bca47e28ad776627f2867b4e40 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 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
17package com.android.server;
18
destradaaea8a8a62014-06-23 18:19:03 -070019import com.android.internal.content.PackageMonitor;
20import com.android.internal.location.ProviderProperties;
21import com.android.internal.location.ProviderRequest;
22import com.android.internal.os.BackgroundThread;
destradaaa4fa3b52014-07-09 10:46:39 -070023import com.android.server.location.ActivityRecognitionProxy;
destradaaea8a8a62014-06-23 18:19:03 -070024import com.android.server.location.FlpHardwareProvider;
25import com.android.server.location.FusedProxy;
26import com.android.server.location.GeocoderProxy;
27import com.android.server.location.GeofenceManager;
28import com.android.server.location.GeofenceProxy;
29import com.android.server.location.GpsLocationProvider;
30import com.android.server.location.GpsMeasurementsProvider;
31import com.android.server.location.LocationBlacklist;
32import com.android.server.location.LocationFudger;
33import com.android.server.location.LocationProviderInterface;
34import com.android.server.location.LocationProviderProxy;
35import com.android.server.location.LocationRequestStatistics;
36import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
37import com.android.server.location.LocationRequestStatistics.PackageStatistics;
38import com.android.server.location.MockProvider;
39import com.android.server.location.PassiveProvider;
40
Dianne Hackborna06de0f2012-12-11 16:34:47 -080041import android.app.AppOpsManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.app.PendingIntent;
Victoria Lease38389b62012-09-30 11:44:22 -070043import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.content.ContentResolver;
45import android.content.Context;
46import android.content.Intent;
Victoria Lease38389b62012-09-30 11:44:22 -070047import android.content.IntentFilter;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070048import android.content.pm.ApplicationInfo;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050049import android.content.pm.PackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.content.pm.PackageManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070051import android.content.pm.PackageManager.NameNotFoundException;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050052import android.content.pm.ResolveInfo;
53import android.content.pm.Signature;
Amith Yamasanib27528d2014-06-05 15:02:10 -070054import android.content.pm.UserInfo;
Mike Lockwood628fd6d2010-01-25 22:46:13 -050055import android.content.res.Resources;
Brian Muramatsubb95cb92012-08-29 10:43:21 -070056import android.database.ContentObserver;
destradaaa4fa3b52014-07-09 10:46:39 -070057import android.hardware.location.ActivityRecognitionHardware;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.location.Address;
Mike Lockwood03ca2162010-04-01 08:10:09 -070059import android.location.Criteria;
Mike Lockwood34901402010-01-04 12:14:21 -050060import android.location.GeocoderParams;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070061import android.location.Geofence;
destradaaea8a8a62014-06-23 18:19:03 -070062import android.location.IGpsMeasurementsListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.location.IGpsStatusListener;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -040064import android.location.IGpsStatusProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065import android.location.ILocationListener;
66import android.location.ILocationManager;
Danke Xie22d1f9f2009-08-18 18:28:45 -040067import android.location.INetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068import android.location.Location;
69import android.location.LocationManager;
70import android.location.LocationProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070071import android.location.LocationRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import android.os.Binder;
73import android.os.Bundle;
74import android.os.Handler;
75import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070076import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077import android.os.Message;
78import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070079import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080import android.os.RemoteException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070081import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070082import android.os.UserHandle;
Amith Yamasanib27528d2014-06-05 15:02:10 -070083import android.os.UserManager;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070084import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080087import android.util.Slog;
Amith Yamasanib27528d2014-06-05 15:02:10 -070088
Mike Lockwood43e33f22010-03-26 10:41:48 -040089import java.io.FileDescriptor;
90import java.io.PrintWriter;
91import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070092import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040093import java.util.HashMap;
94import java.util.HashSet;
95import java.util.List;
96import java.util.Map;
Mike Lockwood43e33f22010-03-26 10:41:48 -040097import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098
99/**
100 * The service class that manages LocationProviders and issues location
101 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 */
Victoria Lease5cd731a2012-12-19 15:04:21 -0800103public class LocationManagerService extends ILocationManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 private static final String TAG = "LocationManagerService";
JP Abgrallf79811e72013-02-01 18:45:05 -0800105 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700106
107 private static final String WAKELOCK_KEY = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108
Victoria Lease37425c32012-10-16 16:08:48 -0700109 // Location resolution level: no location data whatsoever
110 private static final int RESOLUTION_LEVEL_NONE = 0;
111 // Location resolution level: coarse location data only
112 private static final int RESOLUTION_LEVEL_COARSE = 1;
113 // Location resolution level: fine location data
114 private static final int RESOLUTION_LEVEL_FINE = 2;
115
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700117 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700119 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400120 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700121 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
122
123 private static final String NETWORK_LOCATION_SERVICE_ACTION =
Stan Chesnutt39062dd2013-07-22 14:33:30 -0700124 "com.android.location.service.v3.NetworkLocationProvider";
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700125 private static final String FUSED_LOCATION_SERVICE_ACTION =
126 "com.android.location.service.FusedLocationProvider";
127
128 private static final int MSG_LOCATION_CHANGED = 1;
129
David Christie1b9b7b12013-04-15 15:31:11 -0700130 private static final long NANOS_PER_MILLI = 1000000L;
131
David Christie0b837452013-07-29 16:02:13 -0700132 // The maximum interval a location request can have and still be considered "high power".
133 private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
134
Nick Pellyf1be6862012-05-15 10:53:42 -0700135 // Location Providers may sometimes deliver location updates
136 // slightly faster that requested - provide grace period so
137 // we don't unnecessarily filter events that are otherwise on
138 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700139 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700140
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700141 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
142
143 private final Context mContext;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800144 private final AppOpsManager mAppOps;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700145
146 // used internally for synchronization
147 private final Object mLock = new Object();
148
Victoria Lease5cd731a2012-12-19 15:04:21 -0800149 // --- fields below are final after systemReady() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700150 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700151 private GeofenceManager mGeofenceManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700152 private PackageManager mPackageManager;
Victoria Lease0aa28602013-05-29 15:28:26 -0700153 private PowerManager mPowerManager;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700154 private UserManager mUserManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700155 private GeocoderProxy mGeocodeProvider;
156 private IGpsStatusProvider mGpsStatusProvider;
157 private INetInitiatedListener mNetInitiatedListener;
158 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700159 private PassiveProvider mPassiveProvider; // track passive provider for special cases
160 private LocationBlacklist mBlacklist;
destradaaea8a8a62014-06-23 18:19:03 -0700161 private GpsMeasurementsProvider mGpsMeasurementsProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700162
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700163 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 // Set of providers that are explicitly enabled
165 private final Set<String> mEnabledProviders = new HashSet<String>();
166
167 // Set of providers that are explicitly disabled
168 private final Set<String> mDisabledProviders = new HashSet<String>();
169
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700170 // Mock (test) providers
171 private final HashMap<String, MockProvider> mMockProviders =
172 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700174 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400175 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700177 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500178 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700179 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400180
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700181 // real providers, saved here when mocked out
182 private final HashMap<String, LocationProviderInterface> mRealProviders =
183 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700185 // mapping from provider name to provider
186 private final HashMap<String, LocationProviderInterface> mProvidersByName =
187 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700189 // mapping from provider name to all its UpdateRecords
190 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
191 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700192
David Christie2ff96af2014-01-30 16:09:37 -0800193 private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
194
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700195 // mapping from provider name to last known location
196 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197
David Christie1b9b7b12013-04-15 15:31:11 -0700198 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
199 // locations stored here are not fudged for coarse permissions.
200 private final HashMap<String, Location> mLastLocationCoarseInterval =
201 new HashMap<String, Location>();
202
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700203 // all providers that operate over proxy, for authorizing incoming location
204 private final ArrayList<LocationProviderProxy> mProxyProviders =
205 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206
Victoria Lease38389b62012-09-30 11:44:22 -0700207 // current active user on the device - other users are denied location data
208 private int mCurrentUserId = UserHandle.USER_OWNER;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700209 private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_OWNER };
Victoria Lease38389b62012-09-30 11:44:22 -0700210
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700211 public LocationManagerService(Context context) {
212 super();
213 mContext = context;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800214 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800215
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700216 if (D) Log.d(TAG, "Constructed");
217
218 // most startup is deferred until systemReady()
219 }
220
Svetoslav Ganova0027152013-06-25 14:59:53 -0700221 public void systemRunning() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700222 synchronized (mLock) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800223 if (D) Log.d(TAG, "systemReady()");
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700224
Victoria Lease5cd731a2012-12-19 15:04:21 -0800225 // fetch package manager
226 mPackageManager = mContext.getPackageManager();
227
Victoria Lease0aa28602013-05-29 15:28:26 -0700228 // fetch power manager
229 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
Victoria Lease5cd731a2012-12-19 15:04:21 -0800230
231 // prepare worker thread
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700232 mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
Victoria Lease5cd731a2012-12-19 15:04:21 -0800233
234 // prepare mLocationHandler's dependents
235 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
236 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
237 mBlacklist.init();
238 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
239
Dianne Hackbornc2293022013-02-06 23:14:49 -0800240 // Monitor for app ops mode changes.
Dianne Hackborn9bb0ee92013-09-22 12:31:38 -0700241 AppOpsManager.OnOpChangedListener callback
242 = new AppOpsManager.OnOpChangedInternalListener() {
243 public void onOpChanged(int op, String packageName) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800244 synchronized (mLock) {
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700245 for (Receiver receiver : mReceivers.values()) {
246 receiver.updateMonitoring(true);
247 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800248 applyAllProviderRequirementsLocked();
249 }
250 }
251 };
252 mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, callback);
253
Amith Yamasanib27528d2014-06-05 15:02:10 -0700254 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
255 updateUserProfiles(mCurrentUserId);
256
Victoria Lease5cd731a2012-12-19 15:04:21 -0800257 // prepare providers
258 loadProvidersLocked();
259 updateProvidersLocked();
260 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700261
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700262 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700263 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700264 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700265 new ContentObserver(mLocationHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800266 @Override
267 public void onChange(boolean selfChange) {
268 synchronized (mLock) {
269 updateProvidersLocked();
270 }
271 }
272 }, UserHandle.USER_ALL);
273 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700274
Victoria Lease38389b62012-09-30 11:44:22 -0700275 // listen for user change
276 IntentFilter intentFilter = new IntentFilter();
277 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700278 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
279 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
Victoria Lease38389b62012-09-30 11:44:22 -0700280
281 mContext.registerReceiverAsUser(new BroadcastReceiver() {
282 @Override
283 public void onReceive(Context context, Intent intent) {
284 String action = intent.getAction();
285 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
286 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
Amith Yamasanib27528d2014-06-05 15:02:10 -0700287 } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
288 || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
289 updateUserProfiles(mCurrentUserId);
Victoria Lease38389b62012-09-30 11:44:22 -0700290 }
291 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800292 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700293 }
294
Amith Yamasanib27528d2014-06-05 15:02:10 -0700295 /**
296 * Makes a list of userids that are related to the current user. This is
297 * relevant when using managed profiles. Otherwise the list only contains
298 * the current user.
299 *
300 * @param currentUserId the current user, who might have an alter-ego.
301 */
302 void updateUserProfiles(int currentUserId) {
303 List<UserInfo> profiles = mUserManager.getProfiles(currentUserId);
304 synchronized (mLock) {
305 mCurrentUserProfiles = new int[profiles.size()];
306 for (int i = 0; i < mCurrentUserProfiles.length; i++) {
307 mCurrentUserProfiles[i] = profiles.get(i).id;
308 }
309 }
310 }
311
312 /**
313 * Checks if the specified userId matches any of the current foreground
314 * users stored in mCurrentUserProfiles.
315 */
316 private boolean isCurrentProfile(int userId) {
317 synchronized (mLock) {
318 for (int i = 0; i < mCurrentUserProfiles.length; i++) {
319 if (mCurrentUserProfiles[i] == userId) {
320 return true;
321 }
322 }
323 return false;
324 }
325 }
326
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500327 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
328 PackageManager pm = mContext.getPackageManager();
329 String systemPackageName = mContext.getPackageName();
330 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
331
332 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
333 new Intent(FUSED_LOCATION_SERVICE_ACTION),
334 PackageManager.GET_META_DATA, mCurrentUserId);
335 for (ResolveInfo rInfo : rInfos) {
336 String packageName = rInfo.serviceInfo.packageName;
337
338 // Check that the signature is in the list of supported sigs. If it's not in
339 // this list the standard provider binding logic won't bind to it.
340 try {
341 PackageInfo pInfo;
342 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
343 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
344 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
345 ", but has wrong signature, ignoring");
346 continue;
347 }
348 } catch (NameNotFoundException e) {
349 Log.e(TAG, "missing package: " + packageName);
350 continue;
351 }
352
353 // Get the version info
354 if (rInfo.serviceInfo.metaData == null) {
355 Log.w(TAG, "Found fused provider without metadata: " + packageName);
356 continue;
357 }
358
359 int version = rInfo.serviceInfo.metaData.getInt(
360 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
361 if (version == 0) {
362 // This should be the fallback fused location provider.
363
364 // Make sure it's in the system partition.
365 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
366 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
367 continue;
368 }
369
370 // Check that the fallback is signed the same as the OS
371 // as a proxy for coreApp="true"
372 if (pm.checkSignatures(systemPackageName, packageName)
373 != PackageManager.SIGNATURE_MATCH) {
374 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
375 + packageName);
376 continue;
377 }
378
379 // Found a valid fallback.
380 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
381 return;
382 } else {
383 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
384 }
385 }
386
387 throw new IllegalStateException("Unable to find a fused location provider that is in the "
388 + "system partition with version 0 and signed with the platform certificate. "
389 + "Such a package is needed to provide a default fused location provider in the "
390 + "event that no other fused location provider has been installed or is currently "
391 + "available. For example, coreOnly boot mode when decrypting the data "
392 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
393 }
394
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700395 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700396 // create a passive location provider, which is always enabled
397 PassiveProvider passiveProvider = new PassiveProvider(this);
398 addProviderLocked(passiveProvider);
399 mEnabledProviders.add(passiveProvider.getName());
400 mPassiveProvider = passiveProvider;
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700401 // Create a gps location provider
402 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
403 mLocationHandler.getLooper());
Victoria Lease5c24fd02012-10-01 11:00:50 -0700404
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700405 if (GpsLocationProvider.isSupported()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700406 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
407 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
408 addProviderLocked(gpsProvider);
409 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
410 }
destradaaea8a8a62014-06-23 18:19:03 -0700411 mGpsMeasurementsProvider = gpsProvider.getGpsMeasurementsProvider();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700412
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700413 /*
414 Load package name(s) containing location provider support.
415 These packages can contain services implementing location providers:
416 Geocoder Provider, Network Location Provider, and
417 Fused Location Provider. They will each be searched for
418 service components implementing these providers.
419 The location framework also has support for installation
420 of new location providers at run-time. The new package does not
421 have to be explicitly listed here, however it must have a signature
422 that matches the signature of at least one package on this list.
423 */
424 Resources resources = mContext.getResources();
425 ArrayList<String> providerPackageNames = new ArrayList<String>();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500426 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700427 com.android.internal.R.array.config_locationProviderPackageNames);
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500428 if (D) Log.d(TAG, "certificates for location providers pulled from: " +
429 Arrays.toString(pkgs));
430 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
431
432 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700433
434 // bind to network provider
435 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
436 mContext,
437 LocationManager.NETWORK_PROVIDER,
438 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700439 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
440 com.android.internal.R.string.config_networkLocationProviderPackageName,
441 com.android.internal.R.array.config_locationProviderPackageNames,
442 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700443 if (networkProvider != null) {
444 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
445 mProxyProviders.add(networkProvider);
446 addProviderLocked(networkProvider);
447 } else {
448 Slog.w(TAG, "no network location provider found");
449 }
450
451 // bind to fused provider
452 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
453 mContext,
454 LocationManager.FUSED_PROVIDER,
455 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700456 com.android.internal.R.bool.config_enableFusedLocationOverlay,
457 com.android.internal.R.string.config_fusedLocationProviderPackageName,
458 com.android.internal.R.array.config_locationProviderPackageNames,
459 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700460 if (fusedLocationProvider != null) {
461 addProviderLocked(fusedLocationProvider);
462 mProxyProviders.add(fusedLocationProvider);
463 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700464 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700465 } else {
466 Slog.e(TAG, "no fused location provider found",
467 new IllegalStateException("Location service needs a fused location provider"));
468 }
469
470 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700471 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
472 com.android.internal.R.bool.config_enableGeocoderOverlay,
473 com.android.internal.R.string.config_geocoderProviderPackageName,
474 com.android.internal.R.array.config_locationProviderPackageNames,
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800475 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700476 if (mGeocodeProvider == null) {
477 Slog.e(TAG, "no geocoder provider found");
478 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700479
destradaaa4fa3b52014-07-09 10:46:39 -0700480 // bind to fused hardware provider if supported
destradaa5ce66d82014-05-28 18:24:08 -0700481 if (FlpHardwareProvider.isSupported()) {
482 FlpHardwareProvider flpHardwareProvider =
483 FlpHardwareProvider.getInstance(mContext);
destradaacfbdcd22014-04-30 11:29:11 -0700484 FusedProxy fusedProxy = FusedProxy.createAndBind(
485 mContext,
486 mLocationHandler,
487 flpHardwareProvider.getLocationHardware(),
destradaad5323172014-06-12 11:47:05 -0700488 com.android.internal.R.bool.config_enableHardwareFlpOverlay,
489 com.android.internal.R.string.config_hardwareFlpPackageName,
destradaacfbdcd22014-04-30 11:29:11 -0700490 com.android.internal.R.array.config_locationProviderPackageNames);
491 if(fusedProxy == null) {
492 Slog.e(TAG, "Unable to bind FusedProxy.");
493 }
destradaa0682809a2013-08-12 18:50:30 -0700494
destradaacfbdcd22014-04-30 11:29:11 -0700495 // bind to geofence provider
496 GeofenceProxy provider = GeofenceProxy.createAndBind(mContext,
497 com.android.internal.R.bool.config_enableGeofenceOverlay,
498 com.android.internal.R.string.config_geofenceProviderPackageName,
499 com.android.internal.R.array.config_locationProviderPackageNames,
500 mLocationHandler,
501 gpsProvider.getGpsGeofenceProxy(),
502 flpHardwareProvider.getGeofenceHardware());
503 if (provider == null) {
504 Slog.e(TAG, "Unable to bind FLP Geofence proxy.");
505 }
506 } else {
507 Slog.e(TAG, "FLP HAL not supported.");
destradaa0682809a2013-08-12 18:50:30 -0700508 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900509
destradaaa4fa3b52014-07-09 10:46:39 -0700510 // bind to the hardware activity recognition if supported
511 if (ActivityRecognitionHardware.isSupported()) {
512 ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
513 mContext,
514 mLocationHandler,
515 ActivityRecognitionHardware.getInstance(mContext),
516 com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
517 com.android.internal.R.string.config_activityRecognitionHardwarePackageName,
518 com.android.internal.R.array.config_locationProviderPackageNames);
519
520 if (proxy == null) {
521 Slog.e(TAG, "Unable to bind ActivityRecognitionProxy.");
522 }
523 } else {
524 Slog.e(TAG, "Hardware Activity-Recognition not supported.");
525 }
526
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900527 String[] testProviderStrings = resources.getStringArray(
528 com.android.internal.R.array.config_testLocationProviders);
529 for (String testProviderString : testProviderStrings) {
530 String fragments[] = testProviderString.split(",");
531 String name = fragments[0].trim();
532 if (mProvidersByName.get(name) != null) {
533 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
534 }
535 ProviderProperties properties = new ProviderProperties(
536 Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
537 Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
538 Boolean.parseBoolean(fragments[3]) /* requiresCell */,
539 Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
540 Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
541 Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
542 Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
543 Integer.parseInt(fragments[8]) /* powerRequirement */,
544 Integer.parseInt(fragments[9]) /* accuracy */);
545 addTestProviderLocked(name, properties);
546 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700547 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700548
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700550 * Called when the device's active user changes.
551 * @param userId the new active user's UserId
552 */
553 private void switchUser(int userId) {
Jianzheng Zhoud5c69462013-10-10 14:02:09 +0800554 if (mCurrentUserId == userId) {
555 return;
556 }
Victoria Lease83762d22012-10-03 13:51:17 -0700557 mBlacklist.switchUser(userId);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800558 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
Victoria Lease38389b62012-09-30 11:44:22 -0700559 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700560 mLastLocation.clear();
David Christie1b9b7b12013-04-15 15:31:11 -0700561 mLastLocationCoarseInterval.clear();
Victoria Leaseb711d572012-10-02 13:14:11 -0700562 for (LocationProviderInterface p : mProviders) {
Amith Yamasanib27528d2014-06-05 15:02:10 -0700563 updateProviderListenersLocked(p.getName(), false);
Victoria Leaseb711d572012-10-02 13:14:11 -0700564 }
Victoria Lease38389b62012-09-30 11:44:22 -0700565 mCurrentUserId = userId;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700566 updateUserProfiles(userId);
Victoria Leaseb711d572012-10-02 13:14:11 -0700567 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700568 }
569 }
570
571 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
573 * location updates.
574 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700575 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700576 final int mUid; // uid of receiver
577 final int mPid; // pid of receiver
578 final String mPackageName; // package name of receiver
Victoria Lease37425c32012-10-16 16:08:48 -0700579 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700580
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 final ILocationListener mListener;
582 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -0700583 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
David Christie40e57822013-07-30 11:36:48 -0700584 final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700586
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400587 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700588
David Christie0b837452013-07-29 16:02:13 -0700589 // True if app ops has started monitoring this receiver for locations.
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700590 boolean mOpMonitoring;
David Christie0b837452013-07-29 16:02:13 -0700591 // True if app ops has started monitoring this receiver for high power (gps) locations.
592 boolean mOpHighPowerMonitoring;
Mike Lockwood48f17512009-04-23 09:12:08 -0700593 int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -0700594 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700596 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -0700597 String packageName, WorkSource workSource, boolean hideFromAppOps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700600 if (listener != null) {
601 mKey = listener.asBinder();
602 } else {
603 mKey = intent;
604 }
Victoria Lease37425c32012-10-16 16:08:48 -0700605 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700606 mUid = uid;
607 mPid = pid;
608 mPackageName = packageName;
David Christie82edc9b2013-07-19 11:31:42 -0700609 if (workSource != null && workSource.size() <= 0) {
610 workSource = null;
611 }
612 mWorkSource = workSource;
David Christie40e57822013-07-30 11:36:48 -0700613 mHideFromAppOps = hideFromAppOps;
Victoria Lease0aa28602013-05-29 15:28:26 -0700614
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700615 updateMonitoring(true);
616
Victoria Lease0aa28602013-05-29 15:28:26 -0700617 // construct/configure wakelock
618 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -0700619 if (workSource == null) {
620 workSource = new WorkSource(mUid, mPackageName);
621 }
622 mWakeLock.setWorkSource(workSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800623 }
624
625 @Override
626 public boolean equals(Object otherObj) {
627 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700628 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800629 }
630 return false;
631 }
632
633 @Override
634 public int hashCode() {
635 return mKey.hashCode();
636 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400637
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800638 @Override
639 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700640 StringBuilder s = new StringBuilder();
641 s.append("Reciever[");
642 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800643 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700644 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800645 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700646 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700648 for (String p : mUpdateRecords.keySet()) {
649 s.append(" ").append(mUpdateRecords.get(p).toString());
650 }
651 s.append("]");
652 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 }
654
David Christie15b31912013-08-13 15:54:32 -0700655 /**
656 * Update AppOp monitoring for this receiver.
657 *
658 * @param allow If true receiver is currently active, if false it's been removed.
659 */
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700660 public void updateMonitoring(boolean allow) {
David Christie40e57822013-07-30 11:36:48 -0700661 if (mHideFromAppOps) {
662 return;
663 }
664
David Christie15b31912013-08-13 15:54:32 -0700665 boolean requestingLocation = false;
666 boolean requestingHighPowerLocation = false;
667 if (allow) {
668 // See if receiver has any enabled update records. Also note if any update records
669 // are high power (has a high power provider with an interval under a threshold).
670 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
671 if (isAllowedByCurrentUserSettingsLocked(updateRecord.mProvider)) {
672 requestingLocation = true;
673 LocationProviderInterface locationProvider
David Christie2ff96af2014-01-30 16:09:37 -0800674 = mProvidersByName.get(updateRecord.mProvider);
David Christie15b31912013-08-13 15:54:32 -0700675 ProviderProperties properties = locationProvider != null
676 ? locationProvider.getProperties() : null;
677 if (properties != null
678 && properties.mPowerRequirement == Criteria.POWER_HIGH
679 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
680 requestingHighPowerLocation = true;
681 break;
682 }
683 }
684 }
685 }
686
David Christie0b837452013-07-29 16:02:13 -0700687 // First update monitoring of any location request (including high power).
David Christie15b31912013-08-13 15:54:32 -0700688 mOpMonitoring = updateMonitoring(
689 requestingLocation,
690 mOpMonitoring,
David Christie0b837452013-07-29 16:02:13 -0700691 AppOpsManager.OP_MONITOR_LOCATION);
692
693 // Now update monitoring of high power requests only.
David Christiec750c1f2013-08-08 12:56:57 -0700694 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
David Christie15b31912013-08-13 15:54:32 -0700695 mOpHighPowerMonitoring = updateMonitoring(
696 requestingHighPowerLocation,
697 mOpHighPowerMonitoring,
David Christie0b837452013-07-29 16:02:13 -0700698 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
David Christiec750c1f2013-08-08 12:56:57 -0700699 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
David Christie15b31912013-08-13 15:54:32 -0700700 // Send an intent to notify that a high power request has been added/removed.
David Christiec750c1f2013-08-08 12:56:57 -0700701 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
702 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
703 }
David Christie0b837452013-07-29 16:02:13 -0700704 }
705
706 /**
707 * Update AppOps monitoring for a single location request and op type.
708 *
709 * @param allowMonitoring True if monitoring is allowed for this request/op.
710 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
711 * @param op AppOps code for the op to update.
712 * @return True if monitoring is on for this request/op after updating.
713 */
714 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
715 int op) {
716 if (!currentlyMonitoring) {
717 if (allowMonitoring) {
718 return mAppOps.startOpNoThrow(op, mUid, mPackageName)
719 == AppOpsManager.MODE_ALLOWED;
720 }
721 } else {
722 if (!allowMonitoring || mAppOps.checkOpNoThrow(op, mUid, mPackageName)
723 != AppOpsManager.MODE_ALLOWED) {
724 mAppOps.finishOp(op, mUid, mPackageName);
725 return false;
726 }
727 }
728
729 return currentlyMonitoring;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700730 }
731
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732 public boolean isListener() {
733 return mListener != null;
734 }
735
736 public boolean isPendingIntent() {
737 return mPendingIntent != null;
738 }
739
740 public ILocationListener getListener() {
741 if (mListener != null) {
742 return mListener;
743 }
744 throw new IllegalStateException("Request for non-existent listener");
745 }
746
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
748 if (mListener != null) {
749 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700750 synchronized (this) {
751 // synchronize to ensure incrementPendingBroadcastsLocked()
752 // is called before decrementPendingBroadcasts()
753 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700754 // call this after broadcasting so we do not increment
755 // if we throw an exeption.
756 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700757 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 } catch (RemoteException e) {
759 return false;
760 }
761 } else {
762 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800763 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
765 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700766 synchronized (this) {
767 // synchronize to ensure incrementPendingBroadcastsLocked()
768 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700769 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700770 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700771 // call this after broadcasting so we do not increment
772 // if we throw an exeption.
773 incrementPendingBroadcastsLocked();
774 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800775 } catch (PendingIntent.CanceledException e) {
776 return false;
777 }
778 }
779 return true;
780 }
781
782 public boolean callLocationChangedLocked(Location location) {
783 if (mListener != null) {
784 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700785 synchronized (this) {
786 // synchronize to ensure incrementPendingBroadcastsLocked()
787 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -0800788 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -0700789 // call this after broadcasting so we do not increment
790 // if we throw an exeption.
791 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700792 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 } catch (RemoteException e) {
794 return false;
795 }
796 } else {
797 Intent locationChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800798 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700800 synchronized (this) {
801 // synchronize to ensure incrementPendingBroadcastsLocked()
802 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700803 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700804 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700805 // call this after broadcasting so we do not increment
806 // if we throw an exeption.
807 incrementPendingBroadcastsLocked();
808 }
809 } catch (PendingIntent.CanceledException e) {
810 return false;
811 }
812 }
813 return true;
814 }
815
816 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
David Christie15b31912013-08-13 15:54:32 -0700817 // First update AppOp monitoring.
818 // An app may get/lose location access as providers are enabled/disabled.
819 updateMonitoring(true);
820
Mike Lockwood48f17512009-04-23 09:12:08 -0700821 if (mListener != null) {
822 try {
823 synchronized (this) {
824 // synchronize to ensure incrementPendingBroadcastsLocked()
825 // is called before decrementPendingBroadcasts()
826 if (enabled) {
827 mListener.onProviderEnabled(provider);
828 } else {
829 mListener.onProviderDisabled(provider);
830 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700831 // call this after broadcasting so we do not increment
832 // if we throw an exeption.
833 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700834 }
835 } catch (RemoteException e) {
836 return false;
837 }
838 } else {
839 Intent providerIntent = new Intent();
840 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
841 try {
842 synchronized (this) {
843 // synchronize to ensure incrementPendingBroadcastsLocked()
844 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700845 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700846 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700847 // call this after broadcasting so we do not increment
848 // if we throw an exeption.
849 incrementPendingBroadcastsLocked();
850 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800851 } catch (PendingIntent.CanceledException e) {
852 return false;
853 }
854 }
855 return true;
856 }
857
Nick Pellyf1be6862012-05-15 10:53:42 -0700858 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800859 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700860 if (D) Log.d(TAG, "Location listener died");
861
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400862 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800863 removeUpdatesLocked(this);
864 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700865 synchronized (this) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700866 clearPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700867 }
868 }
869
Nick Pellye0fd6932012-07-11 10:26:13 -0700870 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700871 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
872 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400873 synchronized (this) {
874 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700875 }
876 }
877
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400878 // this must be called while synchronized by caller in a synchronized block
879 // containing the sending of the broadcaset
880 private void incrementPendingBroadcastsLocked() {
881 if (mPendingBroadcasts++ == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700882 mWakeLock.acquire();
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400883 }
884 }
885
886 private void decrementPendingBroadcastsLocked() {
887 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700888 if (mWakeLock.isHeld()) {
889 mWakeLock.release();
890 }
891 }
892 }
893
894 public void clearPendingBroadcastsLocked() {
895 if (mPendingBroadcasts > 0) {
896 mPendingBroadcasts = 0;
897 if (mWakeLock.isHeld()) {
898 mWakeLock.release();
899 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700900 }
901 }
902 }
903
Nick Pellye0fd6932012-07-11 10:26:13 -0700904 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700905 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700906 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -0400907 //the receiver list if it is not found. If it is not found then the
908 //LocationListener was removed when it had a pending broadcast and should
909 //not be added back.
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700910 synchronized (mLock) {
911 IBinder binder = listener.asBinder();
912 Receiver receiver = mReceivers.get(binder);
913 if (receiver != null) {
914 synchronized (receiver) {
915 // so wakelock calls will succeed
916 long identity = Binder.clearCallingIdentity();
917 receiver.decrementPendingBroadcastsLocked();
918 Binder.restoreCallingIdentity(identity);
David Christie2ff96af2014-01-30 16:09:37 -0800919 }
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700920 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800921 }
922 }
923
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700924 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400925 mProviders.add(provider);
926 mProvidersByName.put(provider.getName(), provider);
927 }
928
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700929 private void removeProviderLocked(LocationProviderInterface provider) {
930 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400931 mProviders.remove(provider);
932 mProvidersByName.remove(provider.getName());
933 }
934
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800935 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800936 * Returns "true" if access to the specified location provider is allowed by the current
937 * user's settings. Access to all location providers is forbidden to non-location-provider
938 * processes belonging to background users.
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800939 *
940 * @param provider the name of the location provider
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800941 * @return
942 */
Victoria Lease09eeaec2013-02-05 11:34:13 -0800943 private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800944 if (mEnabledProviders.contains(provider)) {
945 return true;
946 }
947 if (mDisabledProviders.contains(provider)) {
948 return false;
949 }
950 // Use system settings
951 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952
Victoria Leaseb711d572012-10-02 13:14:11 -0700953 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800954 }
955
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700956 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800957 * Returns "true" if access to the specified location provider is allowed by the specified
958 * user's settings. Access to all location providers is forbidden to non-location-provider
959 * processes belonging to background users.
960 *
961 * @param provider the name of the location provider
962 * @param uid the requestor's UID
963 * @return
964 */
965 private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
Amith Yamasanib27528d2014-06-05 15:02:10 -0700966 if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -0800967 return false;
968 }
969 return isAllowedByCurrentUserSettingsLocked(provider);
970 }
971
972 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700973 * Returns the permission string associated with the specified resolution level.
974 *
975 * @param resolutionLevel the resolution level
976 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700977 */
Victoria Lease37425c32012-10-16 16:08:48 -0700978 private String getResolutionPermission(int resolutionLevel) {
979 switch (resolutionLevel) {
980 case RESOLUTION_LEVEL_FINE:
981 return android.Manifest.permission.ACCESS_FINE_LOCATION;
982 case RESOLUTION_LEVEL_COARSE:
983 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
984 default:
985 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 }
Victoria Leaseda479c52012-10-15 15:24:16 -0700987 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700988
Victoria Leaseda479c52012-10-15 15:24:16 -0700989 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700990 * Returns the resolution level allowed to the given PID/UID pair.
991 *
992 * @param pid the PID
993 * @param uid the UID
994 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -0700995 */
Victoria Lease37425c32012-10-16 16:08:48 -0700996 private int getAllowedResolutionLevel(int pid, int uid) {
997 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
998 pid, uid) == PackageManager.PERMISSION_GRANTED) {
999 return RESOLUTION_LEVEL_FINE;
1000 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
1001 pid, uid) == PackageManager.PERMISSION_GRANTED) {
1002 return RESOLUTION_LEVEL_COARSE;
1003 } else {
1004 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -07001005 }
Victoria Lease4fab68b2012-09-13 13:20:59 -07001006 }
1007
1008 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001009 * Returns the resolution level allowed to the caller
1010 *
1011 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -07001012 */
Victoria Lease37425c32012-10-16 16:08:48 -07001013 private int getCallerAllowedResolutionLevel() {
1014 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1015 }
1016
1017 /**
1018 * Throw SecurityException if specified resolution level is insufficient to use geofences.
1019 *
1020 * @param allowedResolutionLevel resolution level allowed to caller
1021 */
1022 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1023 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001024 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1025 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 }
1027
Victoria Lease37425c32012-10-16 16:08:48 -07001028 /**
1029 * Return the minimum resolution level required to use the specified location provider.
1030 *
1031 * @param provider the name of the location provider
1032 * @return minimum resolution level required for provider
1033 */
1034 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001035 if (LocationManager.GPS_PROVIDER.equals(provider) ||
1036 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
1037 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001038 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -07001039 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
1040 LocationManager.FUSED_PROVIDER.equals(provider)) {
1041 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001042 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001043 } else {
1044 // mock providers
1045 LocationProviderInterface lp = mMockProviders.get(provider);
1046 if (lp != null) {
1047 ProviderProperties properties = lp.getProperties();
1048 if (properties != null) {
1049 if (properties.mRequiresSatellite) {
1050 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001051 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -07001052 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1053 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001054 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001055 }
1056 }
1057 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001058 }
Victoria Lease37425c32012-10-16 16:08:48 -07001059 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -07001060 }
1061
Victoria Lease37425c32012-10-16 16:08:48 -07001062 /**
1063 * Throw SecurityException if specified resolution level is insufficient to use the named
1064 * location provider.
1065 *
1066 * @param allowedResolutionLevel resolution level allowed to caller
1067 * @param providerName the name of the location provider
1068 */
1069 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
1070 String providerName) {
1071 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
1072 if (allowedResolutionLevel < requiredResolutionLevel) {
1073 switch (requiredResolutionLevel) {
1074 case RESOLUTION_LEVEL_FINE:
1075 throw new SecurityException("\"" + providerName + "\" location provider " +
1076 "requires ACCESS_FINE_LOCATION permission.");
1077 case RESOLUTION_LEVEL_COARSE:
1078 throw new SecurityException("\"" + providerName + "\" location provider " +
1079 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1080 default:
1081 throw new SecurityException("Insufficient permission for \"" + providerName +
1082 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -07001083 }
1084 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001085 }
1086
David Christie82edc9b2013-07-19 11:31:42 -07001087 /**
1088 * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
1089 * for battery).
1090 */
David Christie40e57822013-07-30 11:36:48 -07001091 private void checkDeviceStatsAllowed() {
David Christie82edc9b2013-07-19 11:31:42 -07001092 mContext.enforceCallingOrSelfPermission(
1093 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
1094 }
1095
David Christie40e57822013-07-30 11:36:48 -07001096 private void checkUpdateAppOpsAllowed() {
1097 mContext.enforceCallingOrSelfPermission(
1098 android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
1099 }
1100
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001101 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001102 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1103 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001104 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001105 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001106 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001107 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001108 }
1109 return -1;
1110 }
1111
1112 boolean reportLocationAccessNoThrow(int uid, String packageName, int allowedResolutionLevel) {
1113 int op = resolutionLevelToOp(allowedResolutionLevel);
1114 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001115 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1116 return false;
1117 }
1118 }
1119 return true;
1120 }
1121
1122 boolean checkLocationAccess(int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001123 int op = resolutionLevelToOp(allowedResolutionLevel);
1124 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001125 if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1126 return false;
1127 }
1128 }
1129 return true;
1130 }
1131
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001132 /**
1133 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -07001134 * fused, also including ones that are not permitted to
1135 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001136 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001137 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001138 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001139 ArrayList<String> out;
1140 synchronized (mLock) {
1141 out = new ArrayList<String>(mProviders.size());
1142 for (LocationProviderInterface provider : mProviders) {
1143 String name = provider.getName();
1144 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001145 continue;
1146 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001147 out.add(name);
1148 }
1149 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001150
1151 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001152 return out;
1153 }
1154
Mike Lockwood03ca2162010-04-01 08:10:09 -07001155 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001156 * Return all providers by name, that match criteria and are optionally
1157 * enabled.
1158 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001159 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001160 @Override
1161 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -07001162 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001163 ArrayList<String> out;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001164 int uid = Binder.getCallingUid();;
Victoria Lease269518e2012-10-29 08:25:39 -07001165 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001166 try {
1167 synchronized (mLock) {
1168 out = new ArrayList<String>(mProviders.size());
1169 for (LocationProviderInterface provider : mProviders) {
1170 String name = provider.getName();
1171 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001172 continue;
1173 }
Victoria Lease37425c32012-10-16 16:08:48 -07001174 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001175 if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001176 continue;
1177 }
1178 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
1179 name, provider.getProperties(), criteria)) {
1180 continue;
1181 }
1182 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001183 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001184 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001185 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001186 } finally {
1187 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001188 }
1189
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001190 if (D) Log.d(TAG, "getProviders()=" + out);
1191 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001192 }
1193
1194 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001195 * Return the name of the best provider given a Criteria object.
1196 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001197 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001198 * has been deprecated as well. So this method now uses
1199 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001200 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001201 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001202 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001203 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001204
1205 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001206 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001207 result = pickBest(providers);
1208 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1209 return result;
1210 }
1211 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001212 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001213 result = pickBest(providers);
1214 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1215 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001216 }
1217
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001218 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001219 return null;
1220 }
1221
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001222 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -07001223 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001224 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -07001225 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1226 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001227 } else {
1228 return providers.get(0);
1229 }
1230 }
1231
Nick Pellye0fd6932012-07-11 10:26:13 -07001232 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001233 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
1234 LocationProviderInterface p = mProvidersByName.get(provider);
1235 if (p == null) {
1236 throw new IllegalArgumentException("provider=" + provider);
1237 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001238
1239 boolean result = LocationProvider.propertiesMeetCriteria(
1240 p.getName(), p.getProperties(), criteria);
1241 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1242 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001243 }
1244
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001245 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001246 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001247 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001248 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001249 boolean isEnabled = p.isEnabled();
1250 String name = p.getName();
Victoria Lease09eeaec2013-02-05 11:34:13 -08001251 boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001252 if (isEnabled && !shouldBeEnabled) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001253 updateProviderListenersLocked(name, false);
David Christieb084fef2013-12-18 14:33:57 -08001254 // If any provider has been disabled, clear all last locations for all providers.
1255 // This is to be on the safe side in case a provider has location derived from
1256 // this disabled provider.
1257 mLastLocation.clear();
1258 mLastLocationCoarseInterval.clear();
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001259 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001260 } else if (!isEnabled && shouldBeEnabled) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001261 updateProviderListenersLocked(name, true);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001262 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001263 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001264 }
1265 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001266 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
1267 UserHandle.ALL);
Tom O'Neill40a86c22013-09-03 18:05:13 -07001268 mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
1269 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001270 }
1271 }
1272
Amith Yamasanib27528d2014-06-05 15:02:10 -07001273 private void updateProviderListenersLocked(String provider, boolean enabled) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001274 int listeners = 0;
1275
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001276 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001277 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001278
1279 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001280
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001281 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1282 if (records != null) {
1283 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001284 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001285 UpdateRecord record = records.get(i);
Amith Yamasanib27528d2014-06-05 15:02:10 -07001286 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001287 // Sends a notification message to the receiver
1288 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1289 if (deadReceivers == null) {
1290 deadReceivers = new ArrayList<Receiver>();
1291 }
1292 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001293 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001294 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001295 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001296 }
1297 }
1298
1299 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001300 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001301 removeUpdatesLocked(deadReceivers.get(i));
1302 }
1303 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001304
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001305 if (enabled) {
1306 p.enable();
1307 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001308 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001309 }
1310 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001311 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001312 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001313 }
1314
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001315 private void applyRequirementsLocked(String provider) {
1316 LocationProviderInterface p = mProvidersByName.get(provider);
1317 if (p == null) return;
1318
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001319 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001320 WorkSource worksource = new WorkSource();
1321 ProviderRequest providerRequest = new ProviderRequest();
1322
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001323 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001324 for (UpdateRecord record : records) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001325 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001326 if (checkLocationAccess(record.mReceiver.mUid, record.mReceiver.mPackageName,
1327 record.mReceiver.mAllowedResolutionLevel)) {
1328 LocationRequest locationRequest = record.mRequest;
1329 providerRequest.locationRequests.add(locationRequest);
1330 if (locationRequest.getInterval() < providerRequest.interval) {
1331 providerRequest.reportLocation = true;
1332 providerRequest.interval = locationRequest.getInterval();
1333 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001334 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001335 }
1336 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001337
1338 if (providerRequest.reportLocation) {
1339 // calculate who to blame for power
1340 // This is somewhat arbitrary. We pick a threshold interval
1341 // that is slightly higher that the minimum interval, and
1342 // spread the blame across all applications with a request
1343 // under that threshold.
1344 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1345 for (UpdateRecord record : records) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001346 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001347 LocationRequest locationRequest = record.mRequest;
1348 if (locationRequest.getInterval() <= thresholdInterval) {
David Christiee55c9682013-08-22 10:10:34 -07001349 if (record.mReceiver.mWorkSource != null
1350 && record.mReceiver.mWorkSource.size() > 0
1351 && record.mReceiver.mWorkSource.getName(0) != null) {
David Christie82edc9b2013-07-19 11:31:42 -07001352 // Assign blame to another work source.
David Christiee55c9682013-08-22 10:10:34 -07001353 // Can only assign blame if the WorkSource contains names.
David Christie82edc9b2013-07-19 11:31:42 -07001354 worksource.add(record.mReceiver.mWorkSource);
1355 } else {
1356 // Assign blame to caller.
1357 worksource.add(
1358 record.mReceiver.mUid,
1359 record.mReceiver.mPackageName);
1360 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001361 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001362 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001363 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001364 }
1365 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001366
1367 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1368 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001369 }
1370
1371 private class UpdateRecord {
1372 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001373 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001374 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001375 Location mLastFixBroadcast;
1376 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001377
1378 /**
1379 * Note: must be constructed with lock held.
1380 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001381 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001382 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001383 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001384 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001385
1386 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1387 if (records == null) {
1388 records = new ArrayList<UpdateRecord>();
1389 mRecordsByProvider.put(provider, records);
1390 }
1391 if (!records.contains(this)) {
1392 records.add(this);
1393 }
David Christie2ff96af2014-01-30 16:09:37 -08001394
1395 // Update statistics for historical location requests by package/provider
1396 mRequestStatistics.startRequesting(
1397 mReceiver.mPackageName, provider, request.getInterval());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398 }
1399
1400 /**
David Christie2ff96af2014-01-30 16:09:37 -08001401 * Method to be called when a record will no longer be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001402 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001403 void disposeLocked(boolean removeReceiver) {
David Christie2ff96af2014-01-30 16:09:37 -08001404 mRequestStatistics.stopRequesting(mReceiver.mPackageName, mProvider);
1405
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001406 // remove from mRecordsByProvider
1407 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1408 if (globalRecords != null) {
1409 globalRecords.remove(this);
1410 }
1411
1412 if (!removeReceiver) return; // the caller will handle the rest
1413
1414 // remove from Receiver#mUpdateRecords
1415 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1416 if (receiverRecords != null) {
1417 receiverRecords.remove(this.mProvider);
1418
1419 // and also remove the Receiver if it has no more update records
1420 if (removeReceiver && receiverRecords.size() == 0) {
1421 removeUpdatesLocked(mReceiver);
1422 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001423 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001424 }
1425
1426 @Override
1427 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001428 StringBuilder s = new StringBuilder();
1429 s.append("UpdateRecord[");
1430 s.append(mProvider);
1431 s.append(' ').append(mReceiver.mPackageName).append('(');
1432 s.append(mReceiver.mUid).append(')');
1433 s.append(' ').append(mRequest);
1434 s.append(']');
1435 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001436 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001437 }
1438
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001439 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07001440 String packageName, WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001441 IBinder binder = listener.asBinder();
1442 Receiver receiver = mReceivers.get(binder);
1443 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07001444 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
1445 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001446 mReceivers.put(binder, receiver);
1447
1448 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001449 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001450 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001451 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001452 return null;
1453 }
1454 }
1455 return receiver;
1456 }
1457
David Christie82edc9b2013-07-19 11:31:42 -07001458 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
David Christie40e57822013-07-30 11:36:48 -07001459 WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001460 Receiver receiver = mReceivers.get(intent);
1461 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07001462 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
1463 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001464 mReceivers.put(intent, receiver);
1465 }
1466 return receiver;
1467 }
1468
Victoria Lease37425c32012-10-16 16:08:48 -07001469 /**
1470 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1471 * and consistency requirements.
1472 *
1473 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07001474 * @return a version of request that meets the given resolution and consistency requirements
1475 * @hide
1476 */
1477 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1478 LocationRequest sanitizedRequest = new LocationRequest(request);
1479 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1480 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001481 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001482 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001483 break;
1484 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001485 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001486 break;
1487 }
1488 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001489 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1490 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001491 }
Victoria Lease37425c32012-10-16 16:08:48 -07001492 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1493 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001494 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001495 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001496 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07001497 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001498 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001499 }
Victoria Lease37425c32012-10-16 16:08:48 -07001500 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001501 }
1502
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001503 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001504 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001505 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001506 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001507 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001508 String[] packages = mPackageManager.getPackagesForUid(uid);
1509 if (packages == null) {
1510 throw new SecurityException("invalid UID " + uid);
1511 }
1512 for (String pkg : packages) {
1513 if (packageName.equals(pkg)) return;
1514 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001515 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001516 }
1517
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001518 private void checkPendingIntent(PendingIntent intent) {
1519 if (intent == null) {
1520 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001521 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001522 }
1523
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001524 private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
David Christie40e57822013-07-30 11:36:48 -07001525 int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001526 if (intent == null && listener == null) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001527 throw new IllegalArgumentException("need either listener or intent");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001528 } else if (intent != null && listener != null) {
1529 throw new IllegalArgumentException("cannot register both listener and intent");
1530 } else if (intent != null) {
1531 checkPendingIntent(intent);
David Christie40e57822013-07-30 11:36:48 -07001532 return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001533 } else {
David Christie40e57822013-07-30 11:36:48 -07001534 return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001535 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001536 }
1537
Nick Pellye0fd6932012-07-11 10:26:13 -07001538 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001539 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1540 PendingIntent intent, String packageName) {
1541 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1542 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001543 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1544 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1545 request.getProvider());
David Christie82edc9b2013-07-19 11:31:42 -07001546 WorkSource workSource = request.getWorkSource();
1547 if (workSource != null && workSource.size() > 0) {
David Christie40e57822013-07-30 11:36:48 -07001548 checkDeviceStatsAllowed();
1549 }
1550 boolean hideFromAppOps = request.getHideFromAppOps();
1551 if (hideFromAppOps) {
1552 checkUpdateAppOpsAllowed();
David Christie82edc9b2013-07-19 11:31:42 -07001553 }
Victoria Lease37425c32012-10-16 16:08:48 -07001554 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001555
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001556 final int pid = Binder.getCallingPid();
1557 final int uid = Binder.getCallingUid();
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001558 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001559 long identity = Binder.clearCallingIdentity();
1560 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001561 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
1562 // a location.
Dianne Hackborn35654b62013-01-14 17:38:02 -08001563 checkLocationAccess(uid, packageName, allowedResolutionLevel);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001564
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001565 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001566 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
David Christie40e57822013-07-30 11:36:48 -07001567 packageName, workSource, hideFromAppOps);
Victoria Lease37425c32012-10-16 16:08:48 -07001568 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001569 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001570 } finally {
1571 Binder.restoreCallingIdentity(identity);
1572 }
1573 }
1574
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001575 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1576 int pid, int uid, String packageName) {
1577 // Figure out the provider. Either its explicitly request (legacy use cases), or
1578 // use the fused provider
1579 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1580 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001581 if (name == null) {
1582 throw new IllegalArgumentException("provider name must not be null");
1583 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07001584
1585 if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1586 + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001587 LocationProviderInterface provider = mProvidersByName.get(name);
1588 if (provider == null) {
Victoria Leaseb30f3832013-10-13 12:15:40 -07001589 throw new IllegalArgumentException("provider doesn't exist: " + name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001590 }
1591
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001592 UpdateRecord record = new UpdateRecord(name, request, receiver);
1593 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1594 if (oldRecord != null) {
1595 oldRecord.disposeLocked(false);
1596 }
1597
Victoria Lease09eeaec2013-02-05 11:34:13 -08001598 boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001599 if (isProviderEnabled) {
1600 applyRequirementsLocked(name);
1601 } else {
1602 // Notify the listener that updates are currently disabled
1603 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001604 }
David Christie0b837452013-07-29 16:02:13 -07001605 // Update the monitoring here just in case multiple location requests were added to the
1606 // same receiver (this request may be high power and the initial might not have been).
1607 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001608 }
1609
Nick Pellye0fd6932012-07-11 10:26:13 -07001610 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001611 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1612 String packageName) {
1613 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001614
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001615 final int pid = Binder.getCallingPid();
1616 final int uid = Binder.getCallingUid();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001617
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001618 synchronized (mLock) {
David Christie82edc9b2013-07-19 11:31:42 -07001619 WorkSource workSource = null;
David Christie40e57822013-07-30 11:36:48 -07001620 boolean hideFromAppOps = false;
1621 Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
1622 packageName, workSource, hideFromAppOps);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001623
1624 // providers may use public location API's, need to clear identity
1625 long identity = Binder.clearCallingIdentity();
1626 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001627 removeUpdatesLocked(receiver);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001628 } finally {
1629 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001630 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001631 }
1632 }
1633
1634 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001635 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001636
1637 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1638 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1639 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001640 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001641 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001642 }
1643
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001644 receiver.updateMonitoring(false);
1645
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001646 // Record which providers were associated with this listener
1647 HashSet<String> providers = new HashSet<String>();
1648 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1649 if (oldRecords != null) {
1650 // Call dispose() on the obsolete update records.
1651 for (UpdateRecord record : oldRecords.values()) {
David Christie2ff96af2014-01-30 16:09:37 -08001652 // Update statistics for historical location requests by package/provider
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001653 record.disposeLocked(false);
1654 }
1655 // Accumulate providers
1656 providers.addAll(oldRecords.keySet());
1657 }
1658
1659 // update provider
1660 for (String provider : providers) {
1661 // If provider is already disabled, don't need to do anything
Victoria Lease09eeaec2013-02-05 11:34:13 -08001662 if (!isAllowedByCurrentUserSettingsLocked(provider)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001663 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001664 }
1665
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001666 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001667 }
1668 }
1669
Dianne Hackbornc2293022013-02-06 23:14:49 -08001670 private void applyAllProviderRequirementsLocked() {
1671 for (LocationProviderInterface p : mProviders) {
1672 // If provider is already disabled, don't need to do anything
Dianne Hackborn64d41d72013-02-07 00:33:31 -08001673 if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
Dianne Hackbornc2293022013-02-06 23:14:49 -08001674 continue;
1675 }
1676
1677 applyRequirementsLocked(p.getName());
1678 }
1679 }
1680
Nick Pellye0fd6932012-07-11 10:26:13 -07001681 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001682 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001683 if (D) Log.d(TAG, "getLastLocation: " + request);
1684 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001685 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07001686 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001687 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1688 request.getProvider());
1689 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07001690
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001691 final int uid = Binder.getCallingUid();
1692 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001693 try {
1694 if (mBlacklist.isBlacklisted(packageName)) {
1695 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1696 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001697 return null;
1698 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001699
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001700 if (!reportLocationAccessNoThrow(uid, packageName, allowedResolutionLevel)) {
1701 if (D) Log.d(TAG, "not returning last loc for no op app: " +
1702 packageName);
1703 return null;
1704 }
1705
Victoria Leaseb711d572012-10-02 13:14:11 -07001706 synchronized (mLock) {
1707 // Figure out the provider. Either its explicitly request (deprecated API's),
1708 // or use the fused provider
1709 String name = request.getProvider();
1710 if (name == null) name = LocationManager.FUSED_PROVIDER;
1711 LocationProviderInterface provider = mProvidersByName.get(name);
1712 if (provider == null) return null;
1713
Victoria Lease09eeaec2013-02-05 11:34:13 -08001714 if (!isAllowedByUserSettingsLocked(name, uid)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07001715
David Christie1b9b7b12013-04-15 15:31:11 -07001716 Location location;
1717 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1718 // Make sure that an app with coarse permissions can't get frequent location
1719 // updates by calling LocationManager.getLastKnownLocation repeatedly.
1720 location = mLastLocationCoarseInterval.get(name);
1721 } else {
1722 location = mLastLocation.get(name);
1723 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001724 if (location == null) {
1725 return null;
1726 }
Victoria Lease37425c32012-10-16 16:08:48 -07001727 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001728 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1729 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001730 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07001731 }
Victoria Lease37425c32012-10-16 16:08:48 -07001732 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001733 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07001734 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001735 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001736 return null;
1737 } finally {
1738 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001739 }
1740 }
1741
1742 @Override
1743 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1744 String packageName) {
1745 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001746 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1747 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001748 checkPendingIntent(intent);
1749 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001750 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1751 request.getProvider());
1752 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001753
Victoria Lease37425c32012-10-16 16:08:48 -07001754 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001755
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001756 // geo-fence manager uses the public location API, need to clear identity
1757 int uid = Binder.getCallingUid();
Victoria Lease56e675b2012-11-05 19:25:06 -08001758 if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
1759 // temporary measure until geofences work for secondary users
1760 Log.w(TAG, "proximity alerts are currently available only to the primary user");
1761 return;
1762 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001763 long identity = Binder.clearCallingIdentity();
1764 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001765 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
1766 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001767 } finally {
1768 Binder.restoreCallingIdentity(identity);
1769 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001770 }
1771
1772 @Override
1773 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease37425c32012-10-16 16:08:48 -07001774 checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001775 checkPendingIntent(intent);
1776 checkPackageName(packageName);
1777
1778 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1779
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001780 // geo-fence manager uses the public location API, need to clear identity
1781 long identity = Binder.clearCallingIdentity();
1782 try {
1783 mGeofenceManager.removeFence(geofence, intent);
1784 } finally {
1785 Binder.restoreCallingIdentity(identity);
1786 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001787 }
1788
1789
1790 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001791 public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001792 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001793 return false;
1794 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001795 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1796 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
Victoria Lease37425c32012-10-16 16:08:48 -07001797 LocationManager.GPS_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001798
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001799 final int uid = Binder.getCallingUid();
1800 final long ident = Binder.clearCallingIdentity();
1801 try {
Victoria Lease3d5173d2013-02-05 16:07:32 -08001802 if (!checkLocationAccess(uid, packageName, allowedResolutionLevel)) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001803 return false;
1804 }
1805 } finally {
1806 Binder.restoreCallingIdentity(ident);
1807 }
1808
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001809 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001810 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001811 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001812 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001813 return false;
1814 }
1815 return true;
1816 }
1817
Nick Pellye0fd6932012-07-11 10:26:13 -07001818 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001819 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001820 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001821 try {
1822 mGpsStatusProvider.removeGpsStatusListener(listener);
1823 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001824 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001825 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001826 }
1827 }
1828
Nick Pellye0fd6932012-07-11 10:26:13 -07001829 @Override
destradaaea8a8a62014-06-23 18:19:03 -07001830 public boolean addGpsMeasurementsListener(
1831 IGpsMeasurementsListener listener,
1832 String packageName) {
1833 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1834 checkResolutionLevelIsSufficientForProviderUse(
1835 allowedResolutionLevel,
1836 LocationManager.GPS_PROVIDER);
1837
1838 int uid = Binder.getCallingUid();
1839 long identity = Binder.clearCallingIdentity();
1840 boolean hasLocationAccess;
1841 try {
1842 hasLocationAccess = checkLocationAccess(uid, packageName, allowedResolutionLevel);
1843 } finally {
1844 Binder.restoreCallingIdentity(identity);
1845 }
1846
1847 if (!hasLocationAccess) {
1848 return false;
1849 }
1850
1851 return mGpsMeasurementsProvider.addListener(listener);
1852 }
1853
1854 @Override
1855 public boolean removeGpsMeasurementsListener(IGpsMeasurementsListener listener) {
1856 return mGpsMeasurementsProvider.removeListener(listener);
1857 }
1858
1859 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001860 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001861 if (provider == null) {
1862 // throw NullPointerException to remain compatible with previous implementation
1863 throw new NullPointerException();
1864 }
Victoria Lease37425c32012-10-16 16:08:48 -07001865 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1866 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001867
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001868 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001869 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001870 != PackageManager.PERMISSION_GRANTED)) {
1871 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1872 }
1873
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001874 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001875 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001876 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001877
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001878 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001879 }
1880 }
1881
Nick Pellye0fd6932012-07-11 10:26:13 -07001882 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001883 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001884 if (Binder.getCallingUid() != Process.myUid()) {
1885 throw new SecurityException(
1886 "calling sendNiResponse from outside of the system is not allowed");
1887 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001888 try {
1889 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001890 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001891 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001892 return false;
1893 }
1894 }
1895
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001896 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001897 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001898 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001899 * accessed by the caller
1900 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001901 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001902 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07001903 if (mProvidersByName.get(provider) == null) {
David Christie2ff96af2014-01-30 16:09:37 -08001904 return null;
Laurent Tub7f9d252012-10-16 14:25:00 -07001905 }
1906
Victoria Lease37425c32012-10-16 16:08:48 -07001907 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1908 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001909
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001910 LocationProviderInterface p;
1911 synchronized (mLock) {
1912 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001913 }
1914
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001915 if (p == null) return null;
1916 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001917 }
1918
Nick Pellye0fd6932012-07-11 10:26:13 -07001919 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001920 public boolean isProviderEnabled(String provider) {
Tom O'Neilld5759432013-09-11 11:03:03 -07001921 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
1922 // so we discourage its use
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001923 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1924
Victoria Lease09eeaec2013-02-05 11:34:13 -08001925 int uid = Binder.getCallingUid();
Victoria Lease269518e2012-10-29 08:25:39 -07001926 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001927 try {
1928 synchronized (mLock) {
1929 LocationProviderInterface p = mProvidersByName.get(provider);
1930 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001931
Victoria Lease09eeaec2013-02-05 11:34:13 -08001932 return isAllowedByUserSettingsLocked(provider, uid);
Victoria Leaseb711d572012-10-02 13:14:11 -07001933 }
1934 } finally {
1935 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001936 }
1937 }
1938
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001939 /**
1940 * Returns "true" if the UID belongs to a bound location provider.
1941 *
1942 * @param uid the uid
1943 * @return true if uid belongs to a bound location provider
1944 */
1945 private boolean isUidALocationProvider(int uid) {
1946 if (uid == Process.SYSTEM_UID) {
1947 return true;
1948 }
1949 if (mGeocodeProvider != null) {
David Christie1f141c12014-05-14 15:11:15 -07001950 if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001951 }
1952 for (LocationProviderProxy proxy : mProxyProviders) {
David Christie1f141c12014-05-14 15:11:15 -07001953 if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001954 }
1955 return false;
1956 }
1957
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001958 private void checkCallerIsProvider() {
1959 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1960 == PackageManager.PERMISSION_GRANTED) {
1961 return;
1962 }
1963
1964 // Previously we only used the INSTALL_LOCATION_PROVIDER
1965 // check. But that is system or signature
1966 // protection level which is not flexible enough for
1967 // providers installed oustide the system image. So
1968 // also allow providers with a UID matching the
1969 // currently bound package name
1970
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001971 if (isUidALocationProvider(Binder.getCallingUid())) {
1972 return;
1973 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001974
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001975 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1976 "or UID of a currently bound location provider");
1977 }
1978
David Christie1f141c12014-05-14 15:11:15 -07001979 /**
1980 * Returns true if the given package belongs to the given uid.
1981 */
1982 private boolean doesUidHavePackage(int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001983 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001984 return false;
1985 }
David Christie1f141c12014-05-14 15:11:15 -07001986 String[] packageNames = mPackageManager.getPackagesForUid(uid);
1987 if (packageNames == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001988 return false;
1989 }
David Christie1f141c12014-05-14 15:11:15 -07001990 for (String name : packageNames) {
1991 if (packageName.equals(name)) {
1992 return true;
1993 }
1994 }
1995 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001996 }
1997
Nick Pellye0fd6932012-07-11 10:26:13 -07001998 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001999 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002000 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04002001
Nick Pelly2eeeec22012-07-18 13:13:37 -07002002 if (!location.isComplete()) {
2003 Log.w(TAG, "Dropping incomplete location: " + location);
2004 return;
2005 }
2006
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002007 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
2008 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05002009 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002010 mLocationHandler.sendMessageAtFrontOfQueue(m);
2011 }
2012
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002013
Laurent Tu75defb62012-11-01 16:21:52 -07002014 private static boolean shouldBroadcastSafe(
2015 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002016 // Always broadcast the first update
2017 if (lastLoc == null) {
2018 return true;
2019 }
2020
Nick Pellyf1be6862012-05-15 10:53:42 -07002021 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002022 long minTime = record.mRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07002023 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2024 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002025 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002026 return false;
2027 }
2028
2029 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002030 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002031 if (minDistance > 0.0) {
2032 if (loc.distanceTo(lastLoc) <= minDistance) {
2033 return false;
2034 }
2035 }
2036
Laurent Tu75defb62012-11-01 16:21:52 -07002037 // Check whether sufficient number of udpates is left
2038 if (record.mRequest.getNumUpdates() <= 0) {
2039 return false;
2040 }
2041
2042 // Check whether the expiry date has passed
2043 if (record.mRequest.getExpireAt() < now) {
2044 return false;
2045 }
2046
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002047 return true;
2048 }
2049
Mike Lockwooda4903f22010-02-17 06:42:23 -05002050 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002051 if (D) Log.d(TAG, "incoming location: " + location);
2052
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002053 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05002054 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002055
Laurent Tu60ec50a2012-10-04 17:00:10 -07002056 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002057 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002058 if (p == null) return;
2059
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002060 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07002061 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2062 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002063 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002064 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002065 lastLocation = new Location(provider);
2066 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07002067 } else {
2068 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2069 if (noGPSLocation == null && lastNoGPSLocation != null) {
2070 // New location has no no-GPS location: adopt last no-GPS location. This is set
2071 // directly into location because we do not want to notify COARSE clients.
2072 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
2073 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07002074 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002075 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002076
David Christie1b9b7b12013-04-15 15:31:11 -07002077 // Update last known coarse interval location if enough time has passed.
2078 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
2079 if (lastLocationCoarseInterval == null) {
2080 lastLocationCoarseInterval = new Location(location);
2081 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
2082 }
2083 long timeDiffNanos = location.getElapsedRealtimeNanos()
2084 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
2085 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
2086 lastLocationCoarseInterval.set(location);
2087 }
2088 // Don't ever return a coarse location that is more recent than the allowed update
2089 // interval (i.e. don't allow an app to keep registering and unregistering for
2090 // location updates to overcome the minimum interval).
2091 noGPSLocation =
2092 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2093
Laurent Tu60ec50a2012-10-04 17:00:10 -07002094 // Skip if there are no UpdateRecords for this provider.
2095 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2096 if (records == null || records.size() == 0) return;
2097
Victoria Lease09016ab2012-09-16 12:33:15 -07002098 // Fetch coarse location
2099 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07002100 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002101 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
2102 }
2103
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002104 // Fetch latest status update time
2105 long newStatusUpdateTime = p.getStatusUpdateTime();
2106
David Christie2ff96af2014-01-30 16:09:37 -08002107 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002108 Bundle extras = new Bundle();
2109 int status = p.getStatus(extras);
2110
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002111 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002112 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07002113
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002114 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002115 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002116 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07002117 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07002118
Victoria Lease269518e2012-10-29 08:25:39 -07002119 int receiverUserId = UserHandle.getUserId(receiver.mUid);
Amith Yamasanib27528d2014-06-05 15:02:10 -07002120 if (!isCurrentProfile(receiverUserId) && !isUidALocationProvider(receiver.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07002121 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07002122 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07002123 " (current user: " + mCurrentUserId + ", app: " +
2124 receiver.mPackageName + ")");
2125 }
2126 continue;
2127 }
2128
Nick Pelly4035f5a2012-08-17 14:43:49 -07002129 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
2130 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
2131 receiver.mPackageName);
2132 continue;
2133 }
2134
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002135 if (!reportLocationAccessNoThrow(receiver.mUid, receiver.mPackageName,
2136 receiver.mAllowedResolutionLevel)) {
2137 if (D) Log.d(TAG, "skipping loc update for no op app: " +
2138 receiver.mPackageName);
2139 continue;
2140 }
2141
Victoria Lease09016ab2012-09-16 12:33:15 -07002142 Location notifyLocation = null;
Victoria Lease37425c32012-10-16 16:08:48 -07002143 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2144 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002145 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07002146 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002147 }
Victoria Lease09016ab2012-09-16 12:33:15 -07002148 if (notifyLocation != null) {
2149 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07002150 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002151 if (lastLoc == null) {
2152 lastLoc = new Location(notifyLocation);
2153 r.mLastFixBroadcast = lastLoc;
2154 } else {
2155 lastLoc.set(notifyLocation);
2156 }
2157 if (!receiver.callLocationChangedLocked(notifyLocation)) {
2158 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
2159 receiverDead = true;
2160 }
Laurent Tu75defb62012-11-01 16:21:52 -07002161 r.mRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002162 }
2163 }
2164
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002165 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002166 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07002167 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002168
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002169 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002170 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07002171 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08002172 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07002173 }
2174 }
2175
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002176 // track expired records
Laurent Tu75defb62012-11-01 16:21:52 -07002177 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002178 if (deadUpdateRecords == null) {
2179 deadUpdateRecords = new ArrayList<UpdateRecord>();
2180 }
2181 deadUpdateRecords.add(r);
2182 }
2183 // track dead receivers
2184 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07002185 if (deadReceivers == null) {
2186 deadReceivers = new ArrayList<Receiver>();
2187 }
2188 if (!deadReceivers.contains(receiver)) {
2189 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002190 }
2191 }
2192 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002193
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002194 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002195 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002196 for (Receiver receiver : deadReceivers) {
2197 removeUpdatesLocked(receiver);
2198 }
2199 }
2200 if (deadUpdateRecords != null) {
2201 for (UpdateRecord r : deadUpdateRecords) {
2202 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002203 }
Victoria Lease8b38b292012-12-04 15:04:43 -08002204 applyRequirementsLocked(provider);
2205 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002206 }
2207
2208 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08002209 public LocationWorkerHandler(Looper looper) {
2210 super(looper, null, true);
2211 }
2212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002213 @Override
2214 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002215 switch (msg.what) {
2216 case MSG_LOCATION_CHANGED:
2217 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
2218 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002219 }
2220 }
2221 }
2222
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002223 private boolean isMockProvider(String provider) {
2224 synchronized (mLock) {
2225 return mMockProviders.containsKey(provider);
2226 }
2227 }
2228
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002229 private void handleLocationChanged(Location location, boolean passive) {
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002230 // create a working copy of the incoming Location so that the service can modify it without
2231 // disturbing the caller's copy
2232 Location myLocation = new Location(location);
2233 String provider = myLocation.getProvider();
2234
2235 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
2236 // bit if location did not come from a mock provider because passive/fused providers can
2237 // forward locations from mock providers, and should not grant them legitimacy in doing so.
2238 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
2239 myLocation.setIsFromMockProvider(true);
2240 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08002241
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002242 synchronized (mLock) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08002243 if (isAllowedByCurrentUserSettingsLocked(provider)) {
2244 if (!passive) {
2245 // notify passive provider of the new location
2246 mPassiveProvider.updateLocation(myLocation);
2247 }
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002248 handleLocationChangedLocked(myLocation, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002249 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002250 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002251 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002252
Mike Lockwoode97ae402010-09-29 15:23:46 -04002253 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
2254 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002255 public void onPackageDisappeared(String packageName, int reason) {
2256 // remove all receivers associated with this package name
2257 synchronized (mLock) {
2258 ArrayList<Receiver> deadReceivers = null;
2259
2260 for (Receiver receiver : mReceivers.values()) {
2261 if (receiver.mPackageName.equals(packageName)) {
2262 if (deadReceivers == null) {
2263 deadReceivers = new ArrayList<Receiver>();
2264 }
2265 deadReceivers.add(receiver);
2266 }
2267 }
2268
2269 // perform removal outside of mReceivers loop
2270 if (deadReceivers != null) {
2271 for (Receiver receiver : deadReceivers) {
2272 removeUpdatesLocked(receiver);
2273 }
2274 }
2275 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002276 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04002277 };
2278
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002279 // Geocoder
2280
Nick Pellye0fd6932012-07-11 10:26:13 -07002281 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04002282 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07002283 return mGeocodeProvider != null;
2284 }
2285
Nick Pellye0fd6932012-07-11 10:26:13 -07002286 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002287 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05002288 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04002289 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002290 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
2291 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002292 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002293 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002294 }
2295
Mike Lockwooda55c3212009-04-15 11:10:11 -04002296
Nick Pellye0fd6932012-07-11 10:26:13 -07002297 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002298 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04002299 double lowerLeftLatitude, double lowerLeftLongitude,
2300 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05002301 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04002302
2303 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002304 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
2305 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
2306 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002307 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002308 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002309 }
2310
2311 // Mock Providers
2312
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002313 private void checkMockPermissionsSafe() {
2314 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
2315 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
2316 if (!allowMocks) {
2317 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
2318 }
2319
2320 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
David Christie2ff96af2014-01-30 16:09:37 -08002321 PackageManager.PERMISSION_GRANTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002322 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07002323 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002324 }
2325
Nick Pellye0fd6932012-07-11 10:26:13 -07002326 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002327 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002328 checkMockPermissionsSafe();
2329
Mike Lockwooda4903f22010-02-17 06:42:23 -05002330 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
2331 throw new IllegalArgumentException("Cannot mock the passive location provider");
2332 }
2333
Mike Lockwood86328a92009-10-23 08:38:25 -04002334 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002335 synchronized (mLock) {
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002336 // remove the real provider if we are replacing GPS or network provider
2337 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07002338 || LocationManager.NETWORK_PROVIDER.equals(name)
2339 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002340 LocationProviderInterface p = mProvidersByName.get(name);
2341 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002342 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002343 }
2344 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09002345 addTestProviderLocked(name, properties);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002346 updateProvidersLocked();
2347 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002348 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002349 }
2350
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09002351 private void addTestProviderLocked(String name, ProviderProperties properties) {
2352 if (mProvidersByName.get(name) != null) {
2353 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2354 }
2355 MockProvider provider = new MockProvider(name, this, properties);
2356 addProviderLocked(provider);
2357 mMockProviders.put(name, provider);
2358 mLastLocation.put(name, null);
2359 mLastLocationCoarseInterval.put(name, null);
2360 }
2361
Nick Pellye0fd6932012-07-11 10:26:13 -07002362 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002363 public void removeTestProvider(String provider) {
2364 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002365 synchronized (mLock) {
Tom O'Neill07ee5d12014-03-03 17:48:35 -08002366
2367 // These methods can't be called after removing the test provider, so first make sure
Tom O'Neillfe6d3c52014-03-04 08:26:17 -08002368 // we don't leave anything dangling.
Tom O'Neill07ee5d12014-03-03 17:48:35 -08002369 clearTestProviderEnabled(provider);
2370 clearTestProviderLocation(provider);
2371 clearTestProviderStatus(provider);
2372
You Kima6d0b6f2012-10-28 03:58:44 +09002373 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002374 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002375 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2376 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002377 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002378 removeProviderLocked(mProvidersByName.get(provider));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002379
2380 // reinstate real provider if available
2381 LocationProviderInterface realProvider = mRealProviders.get(provider);
2382 if (realProvider != null) {
2383 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002384 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002385 mLastLocation.put(provider, null);
David Christie1b9b7b12013-04-15 15:31:11 -07002386 mLastLocationCoarseInterval.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002387 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002388 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002389 }
2390 }
2391
Nick Pellye0fd6932012-07-11 10:26:13 -07002392 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002393 public void setTestProviderLocation(String provider, Location loc) {
2394 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002395 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002396 MockProvider mockProvider = mMockProviders.get(provider);
2397 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002398 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2399 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04002400 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2401 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002402 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04002403 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002404 }
2405 }
2406
Nick Pellye0fd6932012-07-11 10:26:13 -07002407 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002408 public void clearTestProviderLocation(String provider) {
2409 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002410 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002411 MockProvider mockProvider = mMockProviders.get(provider);
2412 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002413 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2414 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002415 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002416 }
2417 }
2418
Nick Pellye0fd6932012-07-11 10:26:13 -07002419 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002420 public void setTestProviderEnabled(String provider, boolean enabled) {
2421 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002422 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002423 MockProvider mockProvider = mMockProviders.get(provider);
2424 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002425 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2426 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002427 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002428 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002429 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002430 mEnabledProviders.add(provider);
2431 mDisabledProviders.remove(provider);
2432 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002433 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002434 mEnabledProviders.remove(provider);
2435 mDisabledProviders.add(provider);
2436 }
2437 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002438 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002439 }
2440 }
2441
Nick Pellye0fd6932012-07-11 10:26:13 -07002442 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002443 public void clearTestProviderEnabled(String provider) {
2444 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002445 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002446 MockProvider mockProvider = mMockProviders.get(provider);
2447 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002448 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2449 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002450 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002451 mEnabledProviders.remove(provider);
2452 mDisabledProviders.remove(provider);
2453 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002454 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002455 }
2456 }
2457
Nick Pellye0fd6932012-07-11 10:26:13 -07002458 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002459 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2460 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002461 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002462 MockProvider mockProvider = mMockProviders.get(provider);
2463 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002464 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2465 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002466 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002467 }
2468 }
2469
Nick Pellye0fd6932012-07-11 10:26:13 -07002470 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002471 public void clearTestProviderStatus(String provider) {
2472 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002473 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002474 MockProvider mockProvider = mMockProviders.get(provider);
2475 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002476 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2477 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002478 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002479 }
2480 }
2481
2482 private void log(String log) {
2483 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002484 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002485 }
2486 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002487
2488 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002489 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2490 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2491 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04002492 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002493 + Binder.getCallingPid()
2494 + ", uid=" + Binder.getCallingUid());
2495 return;
2496 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002497
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002498 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002499 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002500 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002501 for (Receiver receiver : mReceivers.values()) {
2502 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002503 }
David Christie2ff96af2014-01-30 16:09:37 -08002504 pw.println(" Active Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002505 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2506 pw.println(" " + entry.getKey() + ":");
2507 for (UpdateRecord record : entry.getValue()) {
2508 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002509 }
2510 }
David Christie2ff96af2014-01-30 16:09:37 -08002511 pw.println(" Historical Records by Provider:");
2512 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
2513 : mRequestStatistics.statistics.entrySet()) {
2514 PackageProviderKey key = entry.getKey();
2515 PackageStatistics stats = entry.getValue();
2516 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
2517 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002518 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002519 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2520 String provider = entry.getKey();
2521 Location location = entry.getValue();
2522 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002523 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002524
David Christie1b9b7b12013-04-15 15:31:11 -07002525 pw.println(" Last Known Locations Coarse Intervals:");
2526 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
2527 String provider = entry.getKey();
2528 Location location = entry.getValue();
2529 pw.println(" " + provider + ": " + location);
2530 }
2531
Nick Pellye0fd6932012-07-11 10:26:13 -07002532 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002533
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002534 if (mEnabledProviders.size() > 0) {
2535 pw.println(" Enabled Providers:");
2536 for (String i : mEnabledProviders) {
2537 pw.println(" " + i);
2538 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002539
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002540 }
2541 if (mDisabledProviders.size() > 0) {
2542 pw.println(" Disabled Providers:");
2543 for (String i : mDisabledProviders) {
2544 pw.println(" " + i);
2545 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002546 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002547 pw.append(" ");
2548 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002549 if (mMockProviders.size() > 0) {
2550 pw.println(" Mock Providers:");
2551 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002552 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002553 }
2554 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002555
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002556 pw.append(" fudger: ");
2557 mLocationFudger.dump(fd, pw, args);
2558
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002559 if (args.length > 0 && "short".equals(args[0])) {
2560 return;
2561 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002562 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002563 pw.print(provider.getName() + " Internal State");
2564 if (provider instanceof LocationProviderProxy) {
2565 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2566 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002567 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002568 pw.println(":");
2569 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002570 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002571 }
2572 }
2573}