blob: 21c9224496b3fd3b4f713c7eec85857fc0e38b27 [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;
destradaa4b3e3932014-07-21 18:01:47 -070031import com.android.server.location.GpsNavigationMessageProvider;
destradaaea8a8a62014-06-23 18:19:03 -070032import com.android.server.location.LocationBlacklist;
33import com.android.server.location.LocationFudger;
34import com.android.server.location.LocationProviderInterface;
35import com.android.server.location.LocationProviderProxy;
36import com.android.server.location.LocationRequestStatistics;
37import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
38import com.android.server.location.LocationRequestStatistics.PackageStatistics;
39import com.android.server.location.MockProvider;
40import com.android.server.location.PassiveProvider;
41
Dianne Hackborna06de0f2012-12-11 16:34:47 -080042import android.app.AppOpsManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.app.PendingIntent;
Victoria Lease38389b62012-09-30 11:44:22 -070044import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.content.ContentResolver;
46import android.content.Context;
47import android.content.Intent;
Victoria Lease38389b62012-09-30 11:44:22 -070048import android.content.IntentFilter;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070049import android.content.pm.ApplicationInfo;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050050import android.content.pm.PackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.content.pm.PackageManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070052import android.content.pm.PackageManager.NameNotFoundException;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050053import android.content.pm.ResolveInfo;
54import android.content.pm.Signature;
Amith Yamasanib27528d2014-06-05 15:02:10 -070055import android.content.pm.UserInfo;
Mike Lockwood628fd6d2010-01-25 22:46:13 -050056import android.content.res.Resources;
Brian Muramatsubb95cb92012-08-29 10:43:21 -070057import android.database.ContentObserver;
destradaaa4fa3b52014-07-09 10:46:39 -070058import android.hardware.location.ActivityRecognitionHardware;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.location.Address;
Mike Lockwood03ca2162010-04-01 08:10:09 -070060import android.location.Criteria;
Mike Lockwood34901402010-01-04 12:14:21 -050061import android.location.GeocoderParams;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070062import android.location.Geofence;
destradaa6568d702014-10-27 12:47:41 -070063import android.location.GpsMeasurementsEvent;
64import android.location.GpsNavigationMessageEvent;
Wei Liu5241a4c2015-05-11 14:00:36 -070065import android.location.IGpsGeofenceHardware;
destradaaea8a8a62014-06-23 18:19:03 -070066import android.location.IGpsMeasurementsListener;
destradaa4b3e3932014-07-21 18:01:47 -070067import android.location.IGpsNavigationMessageListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068import android.location.IGpsStatusListener;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -040069import android.location.IGpsStatusProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070import android.location.ILocationListener;
71import android.location.ILocationManager;
Danke Xie22d1f9f2009-08-18 18:28:45 -040072import android.location.INetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import android.location.Location;
74import android.location.LocationManager;
75import android.location.LocationProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070076import android.location.LocationRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077import android.os.Binder;
78import android.os.Bundle;
79import android.os.Handler;
80import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070081import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082import android.os.Message;
83import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070084import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.os.RemoteException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070086import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070087import android.os.UserHandle;
Amith Yamasanib27528d2014-06-05 15:02:10 -070088import android.os.UserManager;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070089import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080092import android.util.Slog;
Amith Yamasanib27528d2014-06-05 15:02:10 -070093
Mike Lockwood43e33f22010-03-26 10:41:48 -040094import java.io.FileDescriptor;
95import java.io.PrintWriter;
96import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070097import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040098import java.util.HashMap;
99import java.util.HashSet;
100import java.util.List;
101import java.util.Map;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400102import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103
104/**
105 * The service class that manages LocationProviders and issues location
106 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 */
Victoria Lease5cd731a2012-12-19 15:04:21 -0800108public class LocationManagerService extends ILocationManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109 private static final String TAG = "LocationManagerService";
JP Abgrallf79811e72013-02-01 18:45:05 -0800110 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700111
112 private static final String WAKELOCK_KEY = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113
Victoria Lease37425c32012-10-16 16:08:48 -0700114 // Location resolution level: no location data whatsoever
115 private static final int RESOLUTION_LEVEL_NONE = 0;
116 // Location resolution level: coarse location data only
117 private static final int RESOLUTION_LEVEL_COARSE = 1;
118 // Location resolution level: fine location data
119 private static final int RESOLUTION_LEVEL_FINE = 2;
120
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700122 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700124 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400125 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700126 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
127
128 private static final String NETWORK_LOCATION_SERVICE_ACTION =
Stan Chesnutt39062dd2013-07-22 14:33:30 -0700129 "com.android.location.service.v3.NetworkLocationProvider";
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700130 private static final String FUSED_LOCATION_SERVICE_ACTION =
131 "com.android.location.service.FusedLocationProvider";
132
133 private static final int MSG_LOCATION_CHANGED = 1;
134
David Christie1b9b7b12013-04-15 15:31:11 -0700135 private static final long NANOS_PER_MILLI = 1000000L;
136
David Christie0b837452013-07-29 16:02:13 -0700137 // The maximum interval a location request can have and still be considered "high power".
138 private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
139
Nick Pellyf1be6862012-05-15 10:53:42 -0700140 // Location Providers may sometimes deliver location updates
141 // slightly faster that requested - provide grace period so
142 // we don't unnecessarily filter events that are otherwise on
143 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700144 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700145
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700146 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
147
148 private final Context mContext;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800149 private final AppOpsManager mAppOps;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700150
151 // used internally for synchronization
152 private final Object mLock = new Object();
153
Victoria Lease5cd731a2012-12-19 15:04:21 -0800154 // --- fields below are final after systemReady() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700155 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700156 private GeofenceManager mGeofenceManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700157 private PackageManager mPackageManager;
Victoria Lease0aa28602013-05-29 15:28:26 -0700158 private PowerManager mPowerManager;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700159 private UserManager mUserManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700160 private GeocoderProxy mGeocodeProvider;
161 private IGpsStatusProvider mGpsStatusProvider;
162 private INetInitiatedListener mNetInitiatedListener;
163 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700164 private PassiveProvider mPassiveProvider; // track passive provider for special cases
165 private LocationBlacklist mBlacklist;
destradaaea8a8a62014-06-23 18:19:03 -0700166 private GpsMeasurementsProvider mGpsMeasurementsProvider;
destradaa4b3e3932014-07-21 18:01:47 -0700167 private GpsNavigationMessageProvider mGpsNavigationMessageProvider;
Wei Liu5241a4c2015-05-11 14:00:36 -0700168 private IGpsGeofenceHardware mGpsGeofenceProxy;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700169
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700170 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 // Set of providers that are explicitly enabled
172 private final Set<String> mEnabledProviders = new HashSet<String>();
173
174 // Set of providers that are explicitly disabled
175 private final Set<String> mDisabledProviders = new HashSet<String>();
176
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700177 // Mock (test) providers
178 private final HashMap<String, MockProvider> mMockProviders =
179 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700181 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400182 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700184 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500185 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700186 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400187
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700188 // real providers, saved here when mocked out
189 private final HashMap<String, LocationProviderInterface> mRealProviders =
190 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700192 // mapping from provider name to provider
193 private final HashMap<String, LocationProviderInterface> mProvidersByName =
194 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700196 // mapping from provider name to all its UpdateRecords
197 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
198 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700199
David Christie2ff96af2014-01-30 16:09:37 -0800200 private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
201
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700202 // mapping from provider name to last known location
203 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204
David Christie1b9b7b12013-04-15 15:31:11 -0700205 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
206 // locations stored here are not fudged for coarse permissions.
207 private final HashMap<String, Location> mLastLocationCoarseInterval =
208 new HashMap<String, Location>();
209
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700210 // all providers that operate over proxy, for authorizing incoming location
211 private final ArrayList<LocationProviderProxy> mProxyProviders =
212 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213
Victoria Lease38389b62012-09-30 11:44:22 -0700214 // current active user on the device - other users are denied location data
215 private int mCurrentUserId = UserHandle.USER_OWNER;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700216 private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_OWNER };
Victoria Lease38389b62012-09-30 11:44:22 -0700217
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700218 public LocationManagerService(Context context) {
219 super();
220 mContext = context;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800221 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800222
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700223 if (D) Log.d(TAG, "Constructed");
224
225 // most startup is deferred until systemReady()
226 }
227
Svetoslav Ganova0027152013-06-25 14:59:53 -0700228 public void systemRunning() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700229 synchronized (mLock) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800230 if (D) Log.d(TAG, "systemReady()");
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700231
Victoria Lease5cd731a2012-12-19 15:04:21 -0800232 // fetch package manager
233 mPackageManager = mContext.getPackageManager();
234
Victoria Lease0aa28602013-05-29 15:28:26 -0700235 // fetch power manager
236 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
Victoria Lease5cd731a2012-12-19 15:04:21 -0800237
238 // prepare worker thread
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700239 mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
Victoria Lease5cd731a2012-12-19 15:04:21 -0800240
241 // prepare mLocationHandler's dependents
242 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
243 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
244 mBlacklist.init();
245 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
246
Dianne Hackbornc2293022013-02-06 23:14:49 -0800247 // Monitor for app ops mode changes.
Dianne Hackborn9bb0ee92013-09-22 12:31:38 -0700248 AppOpsManager.OnOpChangedListener callback
249 = new AppOpsManager.OnOpChangedInternalListener() {
250 public void onOpChanged(int op, String packageName) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800251 synchronized (mLock) {
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700252 for (Receiver receiver : mReceivers.values()) {
253 receiver.updateMonitoring(true);
254 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800255 applyAllProviderRequirementsLocked();
256 }
257 }
258 };
259 mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, callback);
260
Amith Yamasanib27528d2014-06-05 15:02:10 -0700261 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
262 updateUserProfiles(mCurrentUserId);
263
Victoria Lease5cd731a2012-12-19 15:04:21 -0800264 // prepare providers
265 loadProvidersLocked();
266 updateProvidersLocked();
267 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700268
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700269 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700270 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700271 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700272 new ContentObserver(mLocationHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800273 @Override
274 public void onChange(boolean selfChange) {
275 synchronized (mLock) {
276 updateProvidersLocked();
277 }
278 }
279 }, UserHandle.USER_ALL);
280 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700281
Victoria Lease38389b62012-09-30 11:44:22 -0700282 // listen for user change
283 IntentFilter intentFilter = new IntentFilter();
284 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700285 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
286 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
Victoria Lease38389b62012-09-30 11:44:22 -0700287
288 mContext.registerReceiverAsUser(new BroadcastReceiver() {
289 @Override
290 public void onReceive(Context context, Intent intent) {
291 String action = intent.getAction();
292 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
293 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
Amith Yamasanib27528d2014-06-05 15:02:10 -0700294 } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
295 || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
296 updateUserProfiles(mCurrentUserId);
Victoria Lease38389b62012-09-30 11:44:22 -0700297 }
298 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800299 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700300 }
301
Amith Yamasanib27528d2014-06-05 15:02:10 -0700302 /**
303 * Makes a list of userids that are related to the current user. This is
304 * relevant when using managed profiles. Otherwise the list only contains
305 * the current user.
306 *
307 * @param currentUserId the current user, who might have an alter-ego.
308 */
309 void updateUserProfiles(int currentUserId) {
310 List<UserInfo> profiles = mUserManager.getProfiles(currentUserId);
311 synchronized (mLock) {
312 mCurrentUserProfiles = new int[profiles.size()];
313 for (int i = 0; i < mCurrentUserProfiles.length; i++) {
314 mCurrentUserProfiles[i] = profiles.get(i).id;
315 }
316 }
317 }
318
319 /**
320 * Checks if the specified userId matches any of the current foreground
321 * users stored in mCurrentUserProfiles.
322 */
323 private boolean isCurrentProfile(int userId) {
324 synchronized (mLock) {
325 for (int i = 0; i < mCurrentUserProfiles.length; i++) {
326 if (mCurrentUserProfiles[i] == userId) {
327 return true;
328 }
329 }
330 return false;
331 }
332 }
333
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500334 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
335 PackageManager pm = mContext.getPackageManager();
336 String systemPackageName = mContext.getPackageName();
337 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
338
339 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
340 new Intent(FUSED_LOCATION_SERVICE_ACTION),
341 PackageManager.GET_META_DATA, mCurrentUserId);
342 for (ResolveInfo rInfo : rInfos) {
343 String packageName = rInfo.serviceInfo.packageName;
344
345 // Check that the signature is in the list of supported sigs. If it's not in
346 // this list the standard provider binding logic won't bind to it.
347 try {
348 PackageInfo pInfo;
349 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
350 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
351 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
352 ", but has wrong signature, ignoring");
353 continue;
354 }
355 } catch (NameNotFoundException e) {
356 Log.e(TAG, "missing package: " + packageName);
357 continue;
358 }
359
360 // Get the version info
361 if (rInfo.serviceInfo.metaData == null) {
362 Log.w(TAG, "Found fused provider without metadata: " + packageName);
363 continue;
364 }
365
366 int version = rInfo.serviceInfo.metaData.getInt(
367 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
368 if (version == 0) {
369 // This should be the fallback fused location provider.
370
371 // Make sure it's in the system partition.
372 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
373 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
374 continue;
375 }
376
377 // Check that the fallback is signed the same as the OS
378 // as a proxy for coreApp="true"
379 if (pm.checkSignatures(systemPackageName, packageName)
380 != PackageManager.SIGNATURE_MATCH) {
381 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
382 + packageName);
383 continue;
384 }
385
386 // Found a valid fallback.
387 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
388 return;
389 } else {
390 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
391 }
392 }
393
394 throw new IllegalStateException("Unable to find a fused location provider that is in the "
395 + "system partition with version 0 and signed with the platform certificate. "
396 + "Such a package is needed to provide a default fused location provider in the "
397 + "event that no other fused location provider has been installed or is currently "
398 + "available. For example, coreOnly boot mode when decrypting the data "
399 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
400 }
401
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700402 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700403 // create a passive location provider, which is always enabled
404 PassiveProvider passiveProvider = new PassiveProvider(this);
405 addProviderLocked(passiveProvider);
406 mEnabledProviders.add(passiveProvider.getName());
407 mPassiveProvider = passiveProvider;
408
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700409 if (GpsLocationProvider.isSupported()) {
Wei Liu5241a4c2015-05-11 14:00:36 -0700410 // Create a gps location provider
411 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
412 mLocationHandler.getLooper());
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700413 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
414 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
415 addProviderLocked(gpsProvider);
416 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
Wei Liu5241a4c2015-05-11 14:00:36 -0700417 mGpsMeasurementsProvider = gpsProvider.getGpsMeasurementsProvider();
418 mGpsNavigationMessageProvider = gpsProvider.getGpsNavigationMessageProvider();
419 mGpsGeofenceProxy = gpsProvider.getGpsGeofenceProxy();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700420 }
421
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700422 /*
423 Load package name(s) containing location provider support.
424 These packages can contain services implementing location providers:
425 Geocoder Provider, Network Location Provider, and
426 Fused Location Provider. They will each be searched for
427 service components implementing these providers.
428 The location framework also has support for installation
429 of new location providers at run-time. The new package does not
430 have to be explicitly listed here, however it must have a signature
431 that matches the signature of at least one package on this list.
432 */
433 Resources resources = mContext.getResources();
434 ArrayList<String> providerPackageNames = new ArrayList<String>();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500435 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700436 com.android.internal.R.array.config_locationProviderPackageNames);
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500437 if (D) Log.d(TAG, "certificates for location providers pulled from: " +
438 Arrays.toString(pkgs));
439 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
440
441 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700442
443 // bind to network provider
444 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
445 mContext,
446 LocationManager.NETWORK_PROVIDER,
447 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700448 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
449 com.android.internal.R.string.config_networkLocationProviderPackageName,
450 com.android.internal.R.array.config_locationProviderPackageNames,
451 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700452 if (networkProvider != null) {
453 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
454 mProxyProviders.add(networkProvider);
455 addProviderLocked(networkProvider);
456 } else {
457 Slog.w(TAG, "no network location provider found");
458 }
459
460 // bind to fused provider
461 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
462 mContext,
463 LocationManager.FUSED_PROVIDER,
464 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700465 com.android.internal.R.bool.config_enableFusedLocationOverlay,
466 com.android.internal.R.string.config_fusedLocationProviderPackageName,
467 com.android.internal.R.array.config_locationProviderPackageNames,
468 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700469 if (fusedLocationProvider != null) {
470 addProviderLocked(fusedLocationProvider);
471 mProxyProviders.add(fusedLocationProvider);
472 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700473 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700474 } else {
475 Slog.e(TAG, "no fused location provider found",
476 new IllegalStateException("Location service needs a fused location provider"));
477 }
478
479 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700480 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
481 com.android.internal.R.bool.config_enableGeocoderOverlay,
482 com.android.internal.R.string.config_geocoderProviderPackageName,
483 com.android.internal.R.array.config_locationProviderPackageNames,
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800484 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700485 if (mGeocodeProvider == null) {
486 Slog.e(TAG, "no geocoder provider found");
487 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700488
destradaaa4fa3b52014-07-09 10:46:39 -0700489 // bind to fused hardware provider if supported
destradaabeea4422014-07-30 18:17:21 -0700490 // in devices without support, requesting an instance of FlpHardwareProvider will raise an
491 // exception, so make sure we only do that when supported
492 FlpHardwareProvider flpHardwareProvider;
destradaa5ce66d82014-05-28 18:24:08 -0700493 if (FlpHardwareProvider.isSupported()) {
destradaabeea4422014-07-30 18:17:21 -0700494 flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
destradaaf9a274c2014-07-25 15:11:56 -0700495 FusedProxy fusedProxy = FusedProxy.createAndBind(
496 mContext,
497 mLocationHandler,
498 flpHardwareProvider.getLocationHardware(),
499 com.android.internal.R.bool.config_enableHardwareFlpOverlay,
500 com.android.internal.R.string.config_hardwareFlpPackageName,
501 com.android.internal.R.array.config_locationProviderPackageNames);
502 if (fusedProxy == null) {
503 Slog.e(TAG, "Unable to bind FusedProxy.");
504 }
destradaacfbdcd22014-04-30 11:29:11 -0700505 } else {
destradaabeea4422014-07-30 18:17:21 -0700506 flpHardwareProvider = null;
destradaaf9a274c2014-07-25 15:11:56 -0700507 Slog.e(TAG, "FLP HAL not supported");
508 }
509
510 // bind to geofence provider
511 GeofenceProxy provider = GeofenceProxy.createAndBind(
512 mContext,com.android.internal.R.bool.config_enableGeofenceOverlay,
513 com.android.internal.R.string.config_geofenceProviderPackageName,
514 com.android.internal.R.array.config_locationProviderPackageNames,
515 mLocationHandler,
Wei Liu5241a4c2015-05-11 14:00:36 -0700516 mGpsGeofenceProxy,
destradaabeea4422014-07-30 18:17:21 -0700517 flpHardwareProvider != null ? flpHardwareProvider.getGeofenceHardware() : null);
destradaaf9a274c2014-07-25 15:11:56 -0700518 if (provider == null) {
519 Slog.e(TAG, "Unable to bind FLP Geofence proxy.");
destradaa0682809a2013-08-12 18:50:30 -0700520 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900521
destradaaa4fa3b52014-07-09 10:46:39 -0700522 // bind to the hardware activity recognition if supported
523 if (ActivityRecognitionHardware.isSupported()) {
524 ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
525 mContext,
526 mLocationHandler,
527 ActivityRecognitionHardware.getInstance(mContext),
528 com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
529 com.android.internal.R.string.config_activityRecognitionHardwarePackageName,
530 com.android.internal.R.array.config_locationProviderPackageNames);
531
532 if (proxy == null) {
533 Slog.e(TAG, "Unable to bind ActivityRecognitionProxy.");
534 }
535 } else {
536 Slog.e(TAG, "Hardware Activity-Recognition not supported.");
537 }
538
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900539 String[] testProviderStrings = resources.getStringArray(
540 com.android.internal.R.array.config_testLocationProviders);
541 for (String testProviderString : testProviderStrings) {
542 String fragments[] = testProviderString.split(",");
543 String name = fragments[0].trim();
544 if (mProvidersByName.get(name) != null) {
545 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
546 }
547 ProviderProperties properties = new ProviderProperties(
548 Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
549 Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
550 Boolean.parseBoolean(fragments[3]) /* requiresCell */,
551 Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
552 Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
553 Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
554 Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
555 Integer.parseInt(fragments[8]) /* powerRequirement */,
556 Integer.parseInt(fragments[9]) /* accuracy */);
557 addTestProviderLocked(name, properties);
558 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700559 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700560
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700562 * Called when the device's active user changes.
563 * @param userId the new active user's UserId
564 */
565 private void switchUser(int userId) {
Jianzheng Zhoud5c69462013-10-10 14:02:09 +0800566 if (mCurrentUserId == userId) {
567 return;
568 }
Victoria Lease83762d22012-10-03 13:51:17 -0700569 mBlacklist.switchUser(userId);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800570 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
Victoria Lease38389b62012-09-30 11:44:22 -0700571 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700572 mLastLocation.clear();
David Christie1b9b7b12013-04-15 15:31:11 -0700573 mLastLocationCoarseInterval.clear();
Victoria Leaseb711d572012-10-02 13:14:11 -0700574 for (LocationProviderInterface p : mProviders) {
Amith Yamasanib27528d2014-06-05 15:02:10 -0700575 updateProviderListenersLocked(p.getName(), false);
Victoria Leaseb711d572012-10-02 13:14:11 -0700576 }
Victoria Lease38389b62012-09-30 11:44:22 -0700577 mCurrentUserId = userId;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700578 updateUserProfiles(userId);
Victoria Leaseb711d572012-10-02 13:14:11 -0700579 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700580 }
581 }
582
583 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
585 * location updates.
586 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700587 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700588 final int mUid; // uid of receiver
589 final int mPid; // pid of receiver
590 final String mPackageName; // package name of receiver
Victoria Lease37425c32012-10-16 16:08:48 -0700591 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700592
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 final ILocationListener mListener;
594 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -0700595 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
David Christie40e57822013-07-30 11:36:48 -0700596 final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800597 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700598
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400599 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700600
David Christie0b837452013-07-29 16:02:13 -0700601 // True if app ops has started monitoring this receiver for locations.
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700602 boolean mOpMonitoring;
David Christie0b837452013-07-29 16:02:13 -0700603 // True if app ops has started monitoring this receiver for high power (gps) locations.
604 boolean mOpHighPowerMonitoring;
Mike Lockwood48f17512009-04-23 09:12:08 -0700605 int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -0700606 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700608 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -0700609 String packageName, WorkSource workSource, boolean hideFromAppOps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700612 if (listener != null) {
613 mKey = listener.asBinder();
614 } else {
615 mKey = intent;
616 }
Victoria Lease37425c32012-10-16 16:08:48 -0700617 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700618 mUid = uid;
619 mPid = pid;
620 mPackageName = packageName;
David Christie82edc9b2013-07-19 11:31:42 -0700621 if (workSource != null && workSource.size() <= 0) {
622 workSource = null;
623 }
624 mWorkSource = workSource;
David Christie40e57822013-07-30 11:36:48 -0700625 mHideFromAppOps = hideFromAppOps;
Victoria Lease0aa28602013-05-29 15:28:26 -0700626
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700627 updateMonitoring(true);
628
Victoria Lease0aa28602013-05-29 15:28:26 -0700629 // construct/configure wakelock
630 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -0700631 if (workSource == null) {
632 workSource = new WorkSource(mUid, mPackageName);
633 }
634 mWakeLock.setWorkSource(workSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800635 }
636
637 @Override
638 public boolean equals(Object otherObj) {
639 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700640 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800641 }
642 return false;
643 }
644
645 @Override
646 public int hashCode() {
647 return mKey.hashCode();
648 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400649
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 @Override
651 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700652 StringBuilder s = new StringBuilder();
653 s.append("Reciever[");
654 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800655 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700656 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800657 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700658 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700660 for (String p : mUpdateRecords.keySet()) {
661 s.append(" ").append(mUpdateRecords.get(p).toString());
662 }
663 s.append("]");
664 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 }
666
David Christie15b31912013-08-13 15:54:32 -0700667 /**
668 * Update AppOp monitoring for this receiver.
669 *
670 * @param allow If true receiver is currently active, if false it's been removed.
671 */
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700672 public void updateMonitoring(boolean allow) {
David Christie40e57822013-07-30 11:36:48 -0700673 if (mHideFromAppOps) {
674 return;
675 }
676
David Christie15b31912013-08-13 15:54:32 -0700677 boolean requestingLocation = false;
678 boolean requestingHighPowerLocation = false;
679 if (allow) {
680 // See if receiver has any enabled update records. Also note if any update records
681 // are high power (has a high power provider with an interval under a threshold).
682 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
683 if (isAllowedByCurrentUserSettingsLocked(updateRecord.mProvider)) {
684 requestingLocation = true;
685 LocationProviderInterface locationProvider
David Christie2ff96af2014-01-30 16:09:37 -0800686 = mProvidersByName.get(updateRecord.mProvider);
David Christie15b31912013-08-13 15:54:32 -0700687 ProviderProperties properties = locationProvider != null
688 ? locationProvider.getProperties() : null;
689 if (properties != null
690 && properties.mPowerRequirement == Criteria.POWER_HIGH
691 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
692 requestingHighPowerLocation = true;
693 break;
694 }
695 }
696 }
697 }
698
David Christie0b837452013-07-29 16:02:13 -0700699 // First update monitoring of any location request (including high power).
David Christie15b31912013-08-13 15:54:32 -0700700 mOpMonitoring = updateMonitoring(
701 requestingLocation,
702 mOpMonitoring,
David Christie0b837452013-07-29 16:02:13 -0700703 AppOpsManager.OP_MONITOR_LOCATION);
704
705 // Now update monitoring of high power requests only.
David Christiec750c1f2013-08-08 12:56:57 -0700706 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
David Christie15b31912013-08-13 15:54:32 -0700707 mOpHighPowerMonitoring = updateMonitoring(
708 requestingHighPowerLocation,
709 mOpHighPowerMonitoring,
David Christie0b837452013-07-29 16:02:13 -0700710 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
David Christiec750c1f2013-08-08 12:56:57 -0700711 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
David Christie15b31912013-08-13 15:54:32 -0700712 // Send an intent to notify that a high power request has been added/removed.
David Christiec750c1f2013-08-08 12:56:57 -0700713 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
714 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
715 }
David Christie0b837452013-07-29 16:02:13 -0700716 }
717
718 /**
719 * Update AppOps monitoring for a single location request and op type.
720 *
721 * @param allowMonitoring True if monitoring is allowed for this request/op.
722 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
723 * @param op AppOps code for the op to update.
724 * @return True if monitoring is on for this request/op after updating.
725 */
726 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
727 int op) {
728 if (!currentlyMonitoring) {
729 if (allowMonitoring) {
730 return mAppOps.startOpNoThrow(op, mUid, mPackageName)
731 == AppOpsManager.MODE_ALLOWED;
732 }
733 } else {
734 if (!allowMonitoring || mAppOps.checkOpNoThrow(op, mUid, mPackageName)
735 != AppOpsManager.MODE_ALLOWED) {
736 mAppOps.finishOp(op, mUid, mPackageName);
737 return false;
738 }
739 }
740
741 return currentlyMonitoring;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700742 }
743
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800744 public boolean isListener() {
745 return mListener != null;
746 }
747
748 public boolean isPendingIntent() {
749 return mPendingIntent != null;
750 }
751
752 public ILocationListener getListener() {
753 if (mListener != null) {
754 return mListener;
755 }
756 throw new IllegalStateException("Request for non-existent listener");
757 }
758
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800759 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
760 if (mListener != null) {
761 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700762 synchronized (this) {
763 // synchronize to ensure incrementPendingBroadcastsLocked()
764 // is called before decrementPendingBroadcasts()
765 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700766 // call this after broadcasting so we do not increment
767 // if we throw an exeption.
768 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700769 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 } catch (RemoteException e) {
771 return false;
772 }
773 } else {
774 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800775 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
777 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700778 synchronized (this) {
779 // synchronize to ensure incrementPendingBroadcastsLocked()
780 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700781 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700782 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700783 // call this after broadcasting so we do not increment
784 // if we throw an exeption.
785 incrementPendingBroadcastsLocked();
786 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800787 } catch (PendingIntent.CanceledException e) {
788 return false;
789 }
790 }
791 return true;
792 }
793
794 public boolean callLocationChangedLocked(Location location) {
795 if (mListener != null) {
796 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700797 synchronized (this) {
798 // synchronize to ensure incrementPendingBroadcastsLocked()
799 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -0800800 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -0700801 // call this after broadcasting so we do not increment
802 // if we throw an exeption.
803 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700804 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 } catch (RemoteException e) {
806 return false;
807 }
808 } else {
809 Intent locationChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800810 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800811 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700812 synchronized (this) {
813 // synchronize to ensure incrementPendingBroadcastsLocked()
814 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700815 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700816 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700817 // call this after broadcasting so we do not increment
818 // if we throw an exeption.
819 incrementPendingBroadcastsLocked();
820 }
821 } catch (PendingIntent.CanceledException e) {
822 return false;
823 }
824 }
825 return true;
826 }
827
828 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
David Christie15b31912013-08-13 15:54:32 -0700829 // First update AppOp monitoring.
830 // An app may get/lose location access as providers are enabled/disabled.
831 updateMonitoring(true);
832
Mike Lockwood48f17512009-04-23 09:12:08 -0700833 if (mListener != null) {
834 try {
835 synchronized (this) {
836 // synchronize to ensure incrementPendingBroadcastsLocked()
837 // is called before decrementPendingBroadcasts()
838 if (enabled) {
839 mListener.onProviderEnabled(provider);
840 } else {
841 mListener.onProviderDisabled(provider);
842 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700843 // call this after broadcasting so we do not increment
844 // if we throw an exeption.
845 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700846 }
847 } catch (RemoteException e) {
848 return false;
849 }
850 } else {
851 Intent providerIntent = new Intent();
852 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
853 try {
854 synchronized (this) {
855 // synchronize to ensure incrementPendingBroadcastsLocked()
856 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700857 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700858 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700859 // call this after broadcasting so we do not increment
860 // if we throw an exeption.
861 incrementPendingBroadcastsLocked();
862 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800863 } catch (PendingIntent.CanceledException e) {
864 return false;
865 }
866 }
867 return true;
868 }
869
Nick Pellyf1be6862012-05-15 10:53:42 -0700870 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800871 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700872 if (D) Log.d(TAG, "Location listener died");
873
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400874 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 removeUpdatesLocked(this);
876 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700877 synchronized (this) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700878 clearPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700879 }
880 }
881
Nick Pellye0fd6932012-07-11 10:26:13 -0700882 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700883 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
884 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400885 synchronized (this) {
886 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700887 }
888 }
889
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400890 // this must be called while synchronized by caller in a synchronized block
891 // containing the sending of the broadcaset
892 private void incrementPendingBroadcastsLocked() {
893 if (mPendingBroadcasts++ == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700894 mWakeLock.acquire();
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400895 }
896 }
897
898 private void decrementPendingBroadcastsLocked() {
899 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700900 if (mWakeLock.isHeld()) {
901 mWakeLock.release();
902 }
903 }
904 }
905
906 public void clearPendingBroadcastsLocked() {
907 if (mPendingBroadcasts > 0) {
908 mPendingBroadcasts = 0;
909 if (mWakeLock.isHeld()) {
910 mWakeLock.release();
911 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700912 }
913 }
914 }
915
Nick Pellye0fd6932012-07-11 10:26:13 -0700916 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700917 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700918 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -0400919 //the receiver list if it is not found. If it is not found then the
920 //LocationListener was removed when it had a pending broadcast and should
921 //not be added back.
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700922 synchronized (mLock) {
923 IBinder binder = listener.asBinder();
924 Receiver receiver = mReceivers.get(binder);
925 if (receiver != null) {
926 synchronized (receiver) {
927 // so wakelock calls will succeed
928 long identity = Binder.clearCallingIdentity();
929 receiver.decrementPendingBroadcastsLocked();
930 Binder.restoreCallingIdentity(identity);
David Christie2ff96af2014-01-30 16:09:37 -0800931 }
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700932 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800933 }
934 }
935
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700936 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400937 mProviders.add(provider);
938 mProvidersByName.put(provider.getName(), provider);
939 }
940
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700941 private void removeProviderLocked(LocationProviderInterface provider) {
942 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400943 mProviders.remove(provider);
944 mProvidersByName.remove(provider.getName());
945 }
946
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800947 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800948 * Returns "true" if access to the specified location provider is allowed by the current
949 * user's settings. Access to all location providers is forbidden to non-location-provider
950 * processes belonging to background users.
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800951 *
952 * @param provider the name of the location provider
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800953 * @return
954 */
Victoria Lease09eeaec2013-02-05 11:34:13 -0800955 private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 if (mEnabledProviders.contains(provider)) {
957 return true;
958 }
959 if (mDisabledProviders.contains(provider)) {
960 return false;
961 }
962 // Use system settings
963 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800964
Victoria Leaseb711d572012-10-02 13:14:11 -0700965 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800966 }
967
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700968 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800969 * Returns "true" if access to the specified location provider is allowed by the specified
970 * user's settings. Access to all location providers is forbidden to non-location-provider
971 * processes belonging to background users.
972 *
973 * @param provider the name of the location provider
974 * @param uid the requestor's UID
975 * @return
976 */
977 private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
Amith Yamasanib27528d2014-06-05 15:02:10 -0700978 if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -0800979 return false;
980 }
981 return isAllowedByCurrentUserSettingsLocked(provider);
982 }
983
984 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700985 * Returns the permission string associated with the specified resolution level.
986 *
987 * @param resolutionLevel the resolution level
988 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700989 */
Victoria Lease37425c32012-10-16 16:08:48 -0700990 private String getResolutionPermission(int resolutionLevel) {
991 switch (resolutionLevel) {
992 case RESOLUTION_LEVEL_FINE:
993 return android.Manifest.permission.ACCESS_FINE_LOCATION;
994 case RESOLUTION_LEVEL_COARSE:
995 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
996 default:
997 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 }
Victoria Leaseda479c52012-10-15 15:24:16 -0700999 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001000
Victoria Leaseda479c52012-10-15 15:24:16 -07001001 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001002 * Returns the resolution level allowed to the given PID/UID pair.
1003 *
1004 * @param pid the PID
1005 * @param uid the UID
1006 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -07001007 */
Victoria Lease37425c32012-10-16 16:08:48 -07001008 private int getAllowedResolutionLevel(int pid, int uid) {
1009 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
1010 pid, uid) == PackageManager.PERMISSION_GRANTED) {
1011 return RESOLUTION_LEVEL_FINE;
1012 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
1013 pid, uid) == PackageManager.PERMISSION_GRANTED) {
1014 return RESOLUTION_LEVEL_COARSE;
1015 } else {
1016 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -07001017 }
Victoria Lease4fab68b2012-09-13 13:20:59 -07001018 }
1019
1020 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001021 * Returns the resolution level allowed to the caller
1022 *
1023 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -07001024 */
Victoria Lease37425c32012-10-16 16:08:48 -07001025 private int getCallerAllowedResolutionLevel() {
1026 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1027 }
1028
1029 /**
1030 * Throw SecurityException if specified resolution level is insufficient to use geofences.
1031 *
1032 * @param allowedResolutionLevel resolution level allowed to caller
1033 */
1034 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1035 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001036 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1037 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001038 }
1039
Victoria Lease37425c32012-10-16 16:08:48 -07001040 /**
1041 * Return the minimum resolution level required to use the specified location provider.
1042 *
1043 * @param provider the name of the location provider
1044 * @return minimum resolution level required for provider
1045 */
1046 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001047 if (LocationManager.GPS_PROVIDER.equals(provider) ||
1048 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
1049 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001050 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -07001051 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
1052 LocationManager.FUSED_PROVIDER.equals(provider)) {
1053 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001054 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001055 } else {
1056 // mock providers
1057 LocationProviderInterface lp = mMockProviders.get(provider);
1058 if (lp != null) {
1059 ProviderProperties properties = lp.getProperties();
1060 if (properties != null) {
1061 if (properties.mRequiresSatellite) {
1062 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001063 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -07001064 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1065 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001066 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001067 }
1068 }
1069 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001070 }
Victoria Lease37425c32012-10-16 16:08:48 -07001071 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -07001072 }
1073
Victoria Lease37425c32012-10-16 16:08:48 -07001074 /**
1075 * Throw SecurityException if specified resolution level is insufficient to use the named
1076 * location provider.
1077 *
1078 * @param allowedResolutionLevel resolution level allowed to caller
1079 * @param providerName the name of the location provider
1080 */
1081 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
1082 String providerName) {
1083 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
1084 if (allowedResolutionLevel < requiredResolutionLevel) {
1085 switch (requiredResolutionLevel) {
1086 case RESOLUTION_LEVEL_FINE:
1087 throw new SecurityException("\"" + providerName + "\" location provider " +
1088 "requires ACCESS_FINE_LOCATION permission.");
1089 case RESOLUTION_LEVEL_COARSE:
1090 throw new SecurityException("\"" + providerName + "\" location provider " +
1091 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1092 default:
1093 throw new SecurityException("Insufficient permission for \"" + providerName +
1094 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -07001095 }
1096 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001097 }
1098
David Christie82edc9b2013-07-19 11:31:42 -07001099 /**
1100 * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
1101 * for battery).
1102 */
David Christie40e57822013-07-30 11:36:48 -07001103 private void checkDeviceStatsAllowed() {
David Christie82edc9b2013-07-19 11:31:42 -07001104 mContext.enforceCallingOrSelfPermission(
1105 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
1106 }
1107
David Christie40e57822013-07-30 11:36:48 -07001108 private void checkUpdateAppOpsAllowed() {
1109 mContext.enforceCallingOrSelfPermission(
1110 android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
1111 }
1112
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001113 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001114 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1115 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001116 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001117 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001118 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001119 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001120 }
1121 return -1;
1122 }
1123
1124 boolean reportLocationAccessNoThrow(int uid, String packageName, int allowedResolutionLevel) {
1125 int op = resolutionLevelToOp(allowedResolutionLevel);
1126 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001127 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1128 return false;
1129 }
1130 }
1131 return true;
1132 }
1133
1134 boolean checkLocationAccess(int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001135 int op = resolutionLevelToOp(allowedResolutionLevel);
1136 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001137 if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1138 return false;
1139 }
1140 }
1141 return true;
1142 }
1143
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001144 /**
1145 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -07001146 * fused, also including ones that are not permitted to
1147 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001148 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001149 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001151 ArrayList<String> out;
1152 synchronized (mLock) {
1153 out = new ArrayList<String>(mProviders.size());
1154 for (LocationProviderInterface provider : mProviders) {
1155 String name = provider.getName();
1156 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001157 continue;
1158 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001159 out.add(name);
1160 }
1161 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001162
1163 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001164 return out;
1165 }
1166
Mike Lockwood03ca2162010-04-01 08:10:09 -07001167 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001168 * Return all providers by name, that match criteria and are optionally
1169 * enabled.
1170 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001171 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001172 @Override
1173 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -07001174 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001175 ArrayList<String> out;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001176 int uid = Binder.getCallingUid();;
Victoria Lease269518e2012-10-29 08:25:39 -07001177 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001178 try {
1179 synchronized (mLock) {
1180 out = new ArrayList<String>(mProviders.size());
1181 for (LocationProviderInterface provider : mProviders) {
1182 String name = provider.getName();
1183 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001184 continue;
1185 }
Victoria Lease37425c32012-10-16 16:08:48 -07001186 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001187 if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001188 continue;
1189 }
1190 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
1191 name, provider.getProperties(), criteria)) {
1192 continue;
1193 }
1194 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001195 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001196 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001197 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001198 } finally {
1199 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001200 }
1201
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001202 if (D) Log.d(TAG, "getProviders()=" + out);
1203 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001204 }
1205
1206 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001207 * Return the name of the best provider given a Criteria object.
1208 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001209 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001210 * has been deprecated as well. So this method now uses
1211 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001212 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001213 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001214 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001215 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001216
1217 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001218 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001219 result = pickBest(providers);
1220 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1221 return result;
1222 }
1223 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001224 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001225 result = pickBest(providers);
1226 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1227 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001228 }
1229
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001230 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001231 return null;
1232 }
1233
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001234 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -07001235 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001236 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -07001237 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1238 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001239 } else {
1240 return providers.get(0);
1241 }
1242 }
1243
Nick Pellye0fd6932012-07-11 10:26:13 -07001244 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001245 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
1246 LocationProviderInterface p = mProvidersByName.get(provider);
1247 if (p == null) {
1248 throw new IllegalArgumentException("provider=" + provider);
1249 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001250
1251 boolean result = LocationProvider.propertiesMeetCriteria(
1252 p.getName(), p.getProperties(), criteria);
1253 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1254 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001255 }
1256
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001257 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001258 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001259 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001260 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001261 boolean isEnabled = p.isEnabled();
1262 String name = p.getName();
Victoria Lease09eeaec2013-02-05 11:34:13 -08001263 boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001264 if (isEnabled && !shouldBeEnabled) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001265 updateProviderListenersLocked(name, false);
David Christieb084fef2013-12-18 14:33:57 -08001266 // If any provider has been disabled, clear all last locations for all providers.
1267 // This is to be on the safe side in case a provider has location derived from
1268 // this disabled provider.
1269 mLastLocation.clear();
1270 mLastLocationCoarseInterval.clear();
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001271 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001272 } else if (!isEnabled && shouldBeEnabled) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001273 updateProviderListenersLocked(name, true);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001274 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001275 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001276 }
1277 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001278 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
1279 UserHandle.ALL);
Tom O'Neill40a86c22013-09-03 18:05:13 -07001280 mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
1281 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001282 }
1283 }
1284
Amith Yamasanib27528d2014-06-05 15:02:10 -07001285 private void updateProviderListenersLocked(String provider, boolean enabled) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001286 int listeners = 0;
1287
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001288 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001289 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001290
1291 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001292
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001293 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1294 if (records != null) {
1295 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001296 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001297 UpdateRecord record = records.get(i);
Amith Yamasanib27528d2014-06-05 15:02:10 -07001298 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001299 // Sends a notification message to the receiver
1300 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1301 if (deadReceivers == null) {
1302 deadReceivers = new ArrayList<Receiver>();
1303 }
1304 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001305 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001306 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001307 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001308 }
1309 }
1310
1311 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001312 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001313 removeUpdatesLocked(deadReceivers.get(i));
1314 }
1315 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001316
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001317 if (enabled) {
1318 p.enable();
1319 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001320 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001321 }
1322 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001323 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001324 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001325 }
1326
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001327 private void applyRequirementsLocked(String provider) {
1328 LocationProviderInterface p = mProvidersByName.get(provider);
1329 if (p == null) return;
1330
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001331 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001332 WorkSource worksource = new WorkSource();
1333 ProviderRequest providerRequest = new ProviderRequest();
1334
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001335 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001336 for (UpdateRecord record : records) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001337 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001338 if (checkLocationAccess(record.mReceiver.mUid, record.mReceiver.mPackageName,
1339 record.mReceiver.mAllowedResolutionLevel)) {
1340 LocationRequest locationRequest = record.mRequest;
1341 providerRequest.locationRequests.add(locationRequest);
1342 if (locationRequest.getInterval() < providerRequest.interval) {
1343 providerRequest.reportLocation = true;
1344 providerRequest.interval = locationRequest.getInterval();
1345 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001346 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001347 }
1348 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001349
1350 if (providerRequest.reportLocation) {
1351 // calculate who to blame for power
1352 // This is somewhat arbitrary. We pick a threshold interval
1353 // that is slightly higher that the minimum interval, and
1354 // spread the blame across all applications with a request
1355 // under that threshold.
1356 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1357 for (UpdateRecord record : records) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001358 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001359 LocationRequest locationRequest = record.mRequest;
1360 if (locationRequest.getInterval() <= thresholdInterval) {
David Christiee55c9682013-08-22 10:10:34 -07001361 if (record.mReceiver.mWorkSource != null
1362 && record.mReceiver.mWorkSource.size() > 0
1363 && record.mReceiver.mWorkSource.getName(0) != null) {
David Christie82edc9b2013-07-19 11:31:42 -07001364 // Assign blame to another work source.
David Christiee55c9682013-08-22 10:10:34 -07001365 // Can only assign blame if the WorkSource contains names.
David Christie82edc9b2013-07-19 11:31:42 -07001366 worksource.add(record.mReceiver.mWorkSource);
1367 } else {
1368 // Assign blame to caller.
1369 worksource.add(
1370 record.mReceiver.mUid,
1371 record.mReceiver.mPackageName);
1372 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001373 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001374 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001375 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001376 }
1377 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001378
1379 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1380 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001381 }
1382
1383 private class UpdateRecord {
1384 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001385 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001386 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001387 Location mLastFixBroadcast;
1388 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001389
1390 /**
1391 * Note: must be constructed with lock held.
1392 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001393 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001394 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001395 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001396 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001397
1398 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1399 if (records == null) {
1400 records = new ArrayList<UpdateRecord>();
1401 mRecordsByProvider.put(provider, records);
1402 }
1403 if (!records.contains(this)) {
1404 records.add(this);
1405 }
David Christie2ff96af2014-01-30 16:09:37 -08001406
1407 // Update statistics for historical location requests by package/provider
1408 mRequestStatistics.startRequesting(
1409 mReceiver.mPackageName, provider, request.getInterval());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001410 }
1411
1412 /**
David Christie2ff96af2014-01-30 16:09:37 -08001413 * Method to be called when a record will no longer be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001414 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001415 void disposeLocked(boolean removeReceiver) {
David Christie2ff96af2014-01-30 16:09:37 -08001416 mRequestStatistics.stopRequesting(mReceiver.mPackageName, mProvider);
1417
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001418 // remove from mRecordsByProvider
1419 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1420 if (globalRecords != null) {
1421 globalRecords.remove(this);
1422 }
1423
1424 if (!removeReceiver) return; // the caller will handle the rest
1425
1426 // remove from Receiver#mUpdateRecords
1427 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1428 if (receiverRecords != null) {
1429 receiverRecords.remove(this.mProvider);
1430
1431 // and also remove the Receiver if it has no more update records
1432 if (removeReceiver && receiverRecords.size() == 0) {
1433 removeUpdatesLocked(mReceiver);
1434 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001435 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001436 }
1437
1438 @Override
1439 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001440 StringBuilder s = new StringBuilder();
1441 s.append("UpdateRecord[");
1442 s.append(mProvider);
1443 s.append(' ').append(mReceiver.mPackageName).append('(');
1444 s.append(mReceiver.mUid).append(')');
1445 s.append(' ').append(mRequest);
1446 s.append(']');
1447 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001449 }
1450
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001451 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07001452 String packageName, WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001453 IBinder binder = listener.asBinder();
1454 Receiver receiver = mReceivers.get(binder);
1455 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07001456 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
1457 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001458 mReceivers.put(binder, receiver);
1459
1460 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001461 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001462 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001463 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001464 return null;
1465 }
1466 }
1467 return receiver;
1468 }
1469
David Christie82edc9b2013-07-19 11:31:42 -07001470 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
David Christie40e57822013-07-30 11:36:48 -07001471 WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001472 Receiver receiver = mReceivers.get(intent);
1473 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07001474 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
1475 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001476 mReceivers.put(intent, receiver);
1477 }
1478 return receiver;
1479 }
1480
Victoria Lease37425c32012-10-16 16:08:48 -07001481 /**
1482 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1483 * and consistency requirements.
1484 *
1485 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07001486 * @return a version of request that meets the given resolution and consistency requirements
1487 * @hide
1488 */
1489 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1490 LocationRequest sanitizedRequest = new LocationRequest(request);
1491 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1492 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001493 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001494 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001495 break;
1496 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001497 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001498 break;
1499 }
1500 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001501 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1502 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001503 }
Victoria Lease37425c32012-10-16 16:08:48 -07001504 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1505 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001506 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001507 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001508 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07001509 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001510 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001511 }
Victoria Lease37425c32012-10-16 16:08:48 -07001512 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001513 }
1514
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001515 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001516 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001517 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001518 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001519 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001520 String[] packages = mPackageManager.getPackagesForUid(uid);
1521 if (packages == null) {
1522 throw new SecurityException("invalid UID " + uid);
1523 }
1524 for (String pkg : packages) {
1525 if (packageName.equals(pkg)) return;
1526 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001527 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001528 }
1529
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001530 private void checkPendingIntent(PendingIntent intent) {
1531 if (intent == null) {
1532 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001533 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001534 }
1535
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001536 private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
David Christie40e57822013-07-30 11:36:48 -07001537 int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001538 if (intent == null && listener == null) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001539 throw new IllegalArgumentException("need either listener or intent");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001540 } else if (intent != null && listener != null) {
1541 throw new IllegalArgumentException("cannot register both listener and intent");
1542 } else if (intent != null) {
1543 checkPendingIntent(intent);
David Christie40e57822013-07-30 11:36:48 -07001544 return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001545 } else {
David Christie40e57822013-07-30 11:36:48 -07001546 return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001547 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001548 }
1549
Nick Pellye0fd6932012-07-11 10:26:13 -07001550 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001551 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1552 PendingIntent intent, String packageName) {
1553 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1554 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001555 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1556 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1557 request.getProvider());
David Christie82edc9b2013-07-19 11:31:42 -07001558 WorkSource workSource = request.getWorkSource();
1559 if (workSource != null && workSource.size() > 0) {
David Christie40e57822013-07-30 11:36:48 -07001560 checkDeviceStatsAllowed();
1561 }
1562 boolean hideFromAppOps = request.getHideFromAppOps();
1563 if (hideFromAppOps) {
1564 checkUpdateAppOpsAllowed();
David Christie82edc9b2013-07-19 11:31:42 -07001565 }
Victoria Lease37425c32012-10-16 16:08:48 -07001566 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001567
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001568 final int pid = Binder.getCallingPid();
1569 final int uid = Binder.getCallingUid();
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001570 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001571 long identity = Binder.clearCallingIdentity();
1572 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001573 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
1574 // a location.
Dianne Hackborn35654b62013-01-14 17:38:02 -08001575 checkLocationAccess(uid, packageName, allowedResolutionLevel);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001576
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001577 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001578 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
David Christie40e57822013-07-30 11:36:48 -07001579 packageName, workSource, hideFromAppOps);
Victoria Lease37425c32012-10-16 16:08:48 -07001580 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001581 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001582 } finally {
1583 Binder.restoreCallingIdentity(identity);
1584 }
1585 }
1586
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001587 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1588 int pid, int uid, String packageName) {
1589 // Figure out the provider. Either its explicitly request (legacy use cases), or
1590 // use the fused provider
1591 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1592 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001593 if (name == null) {
1594 throw new IllegalArgumentException("provider name must not be null");
1595 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07001596
1597 if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1598 + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001599 LocationProviderInterface provider = mProvidersByName.get(name);
1600 if (provider == null) {
Victoria Leaseb30f3832013-10-13 12:15:40 -07001601 throw new IllegalArgumentException("provider doesn't exist: " + name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001602 }
1603
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001604 UpdateRecord record = new UpdateRecord(name, request, receiver);
1605 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1606 if (oldRecord != null) {
1607 oldRecord.disposeLocked(false);
1608 }
1609
Victoria Lease09eeaec2013-02-05 11:34:13 -08001610 boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001611 if (isProviderEnabled) {
1612 applyRequirementsLocked(name);
1613 } else {
1614 // Notify the listener that updates are currently disabled
1615 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001616 }
David Christie0b837452013-07-29 16:02:13 -07001617 // Update the monitoring here just in case multiple location requests were added to the
1618 // same receiver (this request may be high power and the initial might not have been).
1619 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001620 }
1621
Nick Pellye0fd6932012-07-11 10:26:13 -07001622 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001623 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1624 String packageName) {
1625 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001626
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001627 final int pid = Binder.getCallingPid();
1628 final int uid = Binder.getCallingUid();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001629
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001630 synchronized (mLock) {
David Christie82edc9b2013-07-19 11:31:42 -07001631 WorkSource workSource = null;
David Christie40e57822013-07-30 11:36:48 -07001632 boolean hideFromAppOps = false;
1633 Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
1634 packageName, workSource, hideFromAppOps);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001635
1636 // providers may use public location API's, need to clear identity
1637 long identity = Binder.clearCallingIdentity();
1638 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001639 removeUpdatesLocked(receiver);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001640 } finally {
1641 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001642 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001643 }
1644 }
1645
1646 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001647 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001648
1649 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1650 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1651 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001652 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001653 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001654 }
1655
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001656 receiver.updateMonitoring(false);
1657
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001658 // Record which providers were associated with this listener
1659 HashSet<String> providers = new HashSet<String>();
1660 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1661 if (oldRecords != null) {
1662 // Call dispose() on the obsolete update records.
1663 for (UpdateRecord record : oldRecords.values()) {
David Christie2ff96af2014-01-30 16:09:37 -08001664 // Update statistics for historical location requests by package/provider
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001665 record.disposeLocked(false);
1666 }
1667 // Accumulate providers
1668 providers.addAll(oldRecords.keySet());
1669 }
1670
1671 // update provider
1672 for (String provider : providers) {
1673 // If provider is already disabled, don't need to do anything
Victoria Lease09eeaec2013-02-05 11:34:13 -08001674 if (!isAllowedByCurrentUserSettingsLocked(provider)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001675 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001676 }
1677
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001678 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001679 }
1680 }
1681
Dianne Hackbornc2293022013-02-06 23:14:49 -08001682 private void applyAllProviderRequirementsLocked() {
1683 for (LocationProviderInterface p : mProviders) {
1684 // If provider is already disabled, don't need to do anything
Dianne Hackborn64d41d72013-02-07 00:33:31 -08001685 if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
Dianne Hackbornc2293022013-02-06 23:14:49 -08001686 continue;
1687 }
1688
1689 applyRequirementsLocked(p.getName());
1690 }
1691 }
1692
Nick Pellye0fd6932012-07-11 10:26:13 -07001693 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001694 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001695 if (D) Log.d(TAG, "getLastLocation: " + request);
1696 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001697 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07001698 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001699 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1700 request.getProvider());
1701 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07001702
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001703 final int uid = Binder.getCallingUid();
1704 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001705 try {
1706 if (mBlacklist.isBlacklisted(packageName)) {
1707 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1708 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001709 return null;
1710 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001711
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001712 if (!reportLocationAccessNoThrow(uid, packageName, allowedResolutionLevel)) {
1713 if (D) Log.d(TAG, "not returning last loc for no op app: " +
1714 packageName);
1715 return null;
1716 }
1717
Victoria Leaseb711d572012-10-02 13:14:11 -07001718 synchronized (mLock) {
1719 // Figure out the provider. Either its explicitly request (deprecated API's),
1720 // or use the fused provider
1721 String name = request.getProvider();
1722 if (name == null) name = LocationManager.FUSED_PROVIDER;
1723 LocationProviderInterface provider = mProvidersByName.get(name);
1724 if (provider == null) return null;
1725
Victoria Lease09eeaec2013-02-05 11:34:13 -08001726 if (!isAllowedByUserSettingsLocked(name, uid)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07001727
David Christie1b9b7b12013-04-15 15:31:11 -07001728 Location location;
1729 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1730 // Make sure that an app with coarse permissions can't get frequent location
1731 // updates by calling LocationManager.getLastKnownLocation repeatedly.
1732 location = mLastLocationCoarseInterval.get(name);
1733 } else {
1734 location = mLastLocation.get(name);
1735 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001736 if (location == null) {
1737 return null;
1738 }
Victoria Lease37425c32012-10-16 16:08:48 -07001739 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001740 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1741 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001742 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07001743 }
Victoria Lease37425c32012-10-16 16:08:48 -07001744 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001745 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07001746 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001747 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001748 return null;
1749 } finally {
1750 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001751 }
1752 }
1753
1754 @Override
1755 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1756 String packageName) {
1757 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001758 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1759 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001760 checkPendingIntent(intent);
1761 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001762 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1763 request.getProvider());
1764 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001765
Victoria Lease37425c32012-10-16 16:08:48 -07001766 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001767
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001768 // geo-fence manager uses the public location API, need to clear identity
1769 int uid = Binder.getCallingUid();
Victoria Lease56e675b2012-11-05 19:25:06 -08001770 if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
1771 // temporary measure until geofences work for secondary users
1772 Log.w(TAG, "proximity alerts are currently available only to the primary user");
1773 return;
1774 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001775 long identity = Binder.clearCallingIdentity();
1776 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001777 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
1778 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001779 } finally {
1780 Binder.restoreCallingIdentity(identity);
1781 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001782 }
1783
1784 @Override
1785 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease37425c32012-10-16 16:08:48 -07001786 checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001787 checkPendingIntent(intent);
1788 checkPackageName(packageName);
1789
1790 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1791
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001792 // geo-fence manager uses the public location API, need to clear identity
1793 long identity = Binder.clearCallingIdentity();
1794 try {
1795 mGeofenceManager.removeFence(geofence, intent);
1796 } finally {
1797 Binder.restoreCallingIdentity(identity);
1798 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001799 }
1800
1801
1802 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001803 public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001804 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1805 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
Victoria Lease37425c32012-10-16 16:08:48 -07001806 LocationManager.GPS_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001807
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001808 final int uid = Binder.getCallingUid();
1809 final long ident = Binder.clearCallingIdentity();
1810 try {
Victoria Lease3d5173d2013-02-05 16:07:32 -08001811 if (!checkLocationAccess(uid, packageName, allowedResolutionLevel)) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001812 return false;
1813 }
1814 } finally {
1815 Binder.restoreCallingIdentity(ident);
1816 }
1817
Takayuki Hoshib254ab6a2014-10-23 16:46:02 +09001818 if (mGpsStatusProvider == null) {
1819 return false;
1820 }
1821
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001822 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001823 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001824 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001825 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001826 return false;
1827 }
1828 return true;
1829 }
1830
Nick Pellye0fd6932012-07-11 10:26:13 -07001831 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001832 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001833 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001834 try {
1835 mGpsStatusProvider.removeGpsStatusListener(listener);
1836 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001837 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001838 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001839 }
1840 }
1841
Nick Pellye0fd6932012-07-11 10:26:13 -07001842 @Override
destradaaea8a8a62014-06-23 18:19:03 -07001843 public boolean addGpsMeasurementsListener(
1844 IGpsMeasurementsListener listener,
1845 String packageName) {
1846 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1847 checkResolutionLevelIsSufficientForProviderUse(
1848 allowedResolutionLevel,
1849 LocationManager.GPS_PROVIDER);
1850
1851 int uid = Binder.getCallingUid();
1852 long identity = Binder.clearCallingIdentity();
1853 boolean hasLocationAccess;
1854 try {
1855 hasLocationAccess = checkLocationAccess(uid, packageName, allowedResolutionLevel);
1856 } finally {
1857 Binder.restoreCallingIdentity(identity);
1858 }
1859
Wei Liu5241a4c2015-05-11 14:00:36 -07001860 if (!hasLocationAccess || mGpsMeasurementsProvider == null) {
destradaaea8a8a62014-06-23 18:19:03 -07001861 return false;
1862 }
destradaaea8a8a62014-06-23 18:19:03 -07001863 return mGpsMeasurementsProvider.addListener(listener);
1864 }
1865
1866 @Override
destradaa6568d702014-10-27 12:47:41 -07001867 public void removeGpsMeasurementsListener(IGpsMeasurementsListener listener) {
Wei Liu5241a4c2015-05-11 14:00:36 -07001868 if (mGpsMeasurementsProvider != null) {
1869 mGpsMeasurementsProvider.removeListener(listener);
1870 }
destradaaea8a8a62014-06-23 18:19:03 -07001871 }
1872
1873 @Override
destradaa4b3e3932014-07-21 18:01:47 -07001874 public boolean addGpsNavigationMessageListener(
1875 IGpsNavigationMessageListener listener,
1876 String packageName) {
1877 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1878 checkResolutionLevelIsSufficientForProviderUse(
1879 allowedResolutionLevel,
1880 LocationManager.GPS_PROVIDER);
1881
1882 int uid = Binder.getCallingUid();
1883 long identity = Binder.clearCallingIdentity();
1884 boolean hasLocationAccess;
1885 try {
1886 hasLocationAccess = checkLocationAccess(uid, packageName, allowedResolutionLevel);
1887 } finally {
1888 Binder.restoreCallingIdentity(identity);
1889 }
1890
Wei Liu5241a4c2015-05-11 14:00:36 -07001891 if (!hasLocationAccess || mGpsNavigationMessageProvider == null) {
destradaa4b3e3932014-07-21 18:01:47 -07001892 return false;
1893 }
1894 return mGpsNavigationMessageProvider.addListener(listener);
1895 }
1896
1897 @Override
destradaa6568d702014-10-27 12:47:41 -07001898 public void removeGpsNavigationMessageListener(IGpsNavigationMessageListener listener) {
Wei Liu5241a4c2015-05-11 14:00:36 -07001899 if (mGpsNavigationMessageProvider != null) {
1900 mGpsNavigationMessageProvider.removeListener(listener);
1901 }
destradaa4b3e3932014-07-21 18:01:47 -07001902 }
1903
1904 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001905 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001906 if (provider == null) {
1907 // throw NullPointerException to remain compatible with previous implementation
1908 throw new NullPointerException();
1909 }
Victoria Lease37425c32012-10-16 16:08:48 -07001910 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1911 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001912
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001913 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001914 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001915 != PackageManager.PERMISSION_GRANTED)) {
1916 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1917 }
1918
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001919 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001920 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001921 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001922
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001923 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001924 }
1925 }
1926
Nick Pellye0fd6932012-07-11 10:26:13 -07001927 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001928 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001929 if (Binder.getCallingUid() != Process.myUid()) {
1930 throw new SecurityException(
1931 "calling sendNiResponse from outside of the system is not allowed");
1932 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001933 try {
1934 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001935 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001936 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001937 return false;
1938 }
1939 }
1940
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001941 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001942 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001943 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001944 * accessed by the caller
1945 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001946 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001947 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07001948 if (mProvidersByName.get(provider) == null) {
David Christie2ff96af2014-01-30 16:09:37 -08001949 return null;
Laurent Tub7f9d252012-10-16 14:25:00 -07001950 }
1951
Victoria Lease37425c32012-10-16 16:08:48 -07001952 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1953 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001954
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001955 LocationProviderInterface p;
1956 synchronized (mLock) {
1957 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001958 }
1959
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001960 if (p == null) return null;
1961 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001962 }
1963
Nick Pellye0fd6932012-07-11 10:26:13 -07001964 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001965 public boolean isProviderEnabled(String provider) {
Tom O'Neilld5759432013-09-11 11:03:03 -07001966 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
1967 // so we discourage its use
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001968 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1969
Victoria Lease09eeaec2013-02-05 11:34:13 -08001970 int uid = Binder.getCallingUid();
Victoria Lease269518e2012-10-29 08:25:39 -07001971 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001972 try {
1973 synchronized (mLock) {
1974 LocationProviderInterface p = mProvidersByName.get(provider);
1975 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001976
Victoria Lease09eeaec2013-02-05 11:34:13 -08001977 return isAllowedByUserSettingsLocked(provider, uid);
Victoria Leaseb711d572012-10-02 13:14:11 -07001978 }
1979 } finally {
1980 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001981 }
1982 }
1983
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001984 /**
1985 * Returns "true" if the UID belongs to a bound location provider.
1986 *
1987 * @param uid the uid
1988 * @return true if uid belongs to a bound location provider
1989 */
1990 private boolean isUidALocationProvider(int uid) {
1991 if (uid == Process.SYSTEM_UID) {
1992 return true;
1993 }
1994 if (mGeocodeProvider != null) {
David Christie1f141c12014-05-14 15:11:15 -07001995 if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001996 }
1997 for (LocationProviderProxy proxy : mProxyProviders) {
David Christie1f141c12014-05-14 15:11:15 -07001998 if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001999 }
2000 return false;
2001 }
2002
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002003 private void checkCallerIsProvider() {
2004 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
2005 == PackageManager.PERMISSION_GRANTED) {
2006 return;
2007 }
2008
2009 // Previously we only used the INSTALL_LOCATION_PROVIDER
2010 // check. But that is system or signature
2011 // protection level which is not flexible enough for
2012 // providers installed oustide the system image. So
2013 // also allow providers with a UID matching the
2014 // currently bound package name
2015
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002016 if (isUidALocationProvider(Binder.getCallingUid())) {
2017 return;
2018 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002019
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002020 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
2021 "or UID of a currently bound location provider");
2022 }
2023
David Christie1f141c12014-05-14 15:11:15 -07002024 /**
2025 * Returns true if the given package belongs to the given uid.
2026 */
2027 private boolean doesUidHavePackage(int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002028 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002029 return false;
2030 }
David Christie1f141c12014-05-14 15:11:15 -07002031 String[] packageNames = mPackageManager.getPackagesForUid(uid);
2032 if (packageNames == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002033 return false;
2034 }
David Christie1f141c12014-05-14 15:11:15 -07002035 for (String name : packageNames) {
2036 if (packageName.equals(name)) {
2037 return true;
2038 }
2039 }
2040 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002041 }
2042
Nick Pellye0fd6932012-07-11 10:26:13 -07002043 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05002044 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002045 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04002046
Nick Pelly2eeeec22012-07-18 13:13:37 -07002047 if (!location.isComplete()) {
2048 Log.w(TAG, "Dropping incomplete location: " + location);
2049 return;
2050 }
2051
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002052 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
2053 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05002054 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002055 mLocationHandler.sendMessageAtFrontOfQueue(m);
2056 }
2057
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002058
Laurent Tu75defb62012-11-01 16:21:52 -07002059 private static boolean shouldBroadcastSafe(
2060 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002061 // Always broadcast the first update
2062 if (lastLoc == null) {
2063 return true;
2064 }
2065
Nick Pellyf1be6862012-05-15 10:53:42 -07002066 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002067 long minTime = record.mRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07002068 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2069 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002070 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002071 return false;
2072 }
2073
2074 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002075 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002076 if (minDistance > 0.0) {
2077 if (loc.distanceTo(lastLoc) <= minDistance) {
2078 return false;
2079 }
2080 }
2081
Laurent Tu75defb62012-11-01 16:21:52 -07002082 // Check whether sufficient number of udpates is left
2083 if (record.mRequest.getNumUpdates() <= 0) {
2084 return false;
2085 }
2086
2087 // Check whether the expiry date has passed
2088 if (record.mRequest.getExpireAt() < now) {
2089 return false;
2090 }
2091
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002092 return true;
2093 }
2094
Mike Lockwooda4903f22010-02-17 06:42:23 -05002095 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002096 if (D) Log.d(TAG, "incoming location: " + location);
2097
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002098 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05002099 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002100
Laurent Tu60ec50a2012-10-04 17:00:10 -07002101 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002102 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002103 if (p == null) return;
2104
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002105 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07002106 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2107 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002108 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002109 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002110 lastLocation = new Location(provider);
2111 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07002112 } else {
2113 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2114 if (noGPSLocation == null && lastNoGPSLocation != null) {
2115 // New location has no no-GPS location: adopt last no-GPS location. This is set
2116 // directly into location because we do not want to notify COARSE clients.
2117 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
2118 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07002119 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002120 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002121
David Christie1b9b7b12013-04-15 15:31:11 -07002122 // Update last known coarse interval location if enough time has passed.
2123 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
2124 if (lastLocationCoarseInterval == null) {
2125 lastLocationCoarseInterval = new Location(location);
2126 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
2127 }
2128 long timeDiffNanos = location.getElapsedRealtimeNanos()
2129 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
2130 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
2131 lastLocationCoarseInterval.set(location);
2132 }
2133 // Don't ever return a coarse location that is more recent than the allowed update
2134 // interval (i.e. don't allow an app to keep registering and unregistering for
2135 // location updates to overcome the minimum interval).
2136 noGPSLocation =
2137 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2138
Laurent Tu60ec50a2012-10-04 17:00:10 -07002139 // Skip if there are no UpdateRecords for this provider.
2140 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2141 if (records == null || records.size() == 0) return;
2142
Victoria Lease09016ab2012-09-16 12:33:15 -07002143 // Fetch coarse location
2144 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07002145 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002146 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
2147 }
2148
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002149 // Fetch latest status update time
2150 long newStatusUpdateTime = p.getStatusUpdateTime();
2151
David Christie2ff96af2014-01-30 16:09:37 -08002152 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002153 Bundle extras = new Bundle();
2154 int status = p.getStatus(extras);
2155
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002156 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002157 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07002158
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002159 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002160 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002161 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07002162 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07002163
Victoria Lease269518e2012-10-29 08:25:39 -07002164 int receiverUserId = UserHandle.getUserId(receiver.mUid);
Amith Yamasanib27528d2014-06-05 15:02:10 -07002165 if (!isCurrentProfile(receiverUserId) && !isUidALocationProvider(receiver.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07002166 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07002167 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07002168 " (current user: " + mCurrentUserId + ", app: " +
2169 receiver.mPackageName + ")");
2170 }
2171 continue;
2172 }
2173
Nick Pelly4035f5a2012-08-17 14:43:49 -07002174 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
2175 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
2176 receiver.mPackageName);
2177 continue;
2178 }
2179
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002180 if (!reportLocationAccessNoThrow(receiver.mUid, receiver.mPackageName,
2181 receiver.mAllowedResolutionLevel)) {
2182 if (D) Log.d(TAG, "skipping loc update for no op app: " +
2183 receiver.mPackageName);
2184 continue;
2185 }
2186
Victoria Lease09016ab2012-09-16 12:33:15 -07002187 Location notifyLocation = null;
Victoria Lease37425c32012-10-16 16:08:48 -07002188 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2189 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002190 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07002191 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002192 }
Victoria Lease09016ab2012-09-16 12:33:15 -07002193 if (notifyLocation != null) {
2194 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07002195 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002196 if (lastLoc == null) {
2197 lastLoc = new Location(notifyLocation);
2198 r.mLastFixBroadcast = lastLoc;
2199 } else {
2200 lastLoc.set(notifyLocation);
2201 }
2202 if (!receiver.callLocationChangedLocked(notifyLocation)) {
2203 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
2204 receiverDead = true;
2205 }
Laurent Tu75defb62012-11-01 16:21:52 -07002206 r.mRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002207 }
2208 }
2209
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002210 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002211 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07002212 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002213
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002214 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002215 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07002216 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08002217 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07002218 }
2219 }
2220
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002221 // track expired records
Laurent Tu75defb62012-11-01 16:21:52 -07002222 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002223 if (deadUpdateRecords == null) {
2224 deadUpdateRecords = new ArrayList<UpdateRecord>();
2225 }
2226 deadUpdateRecords.add(r);
2227 }
2228 // track dead receivers
2229 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07002230 if (deadReceivers == null) {
2231 deadReceivers = new ArrayList<Receiver>();
2232 }
2233 if (!deadReceivers.contains(receiver)) {
2234 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002235 }
2236 }
2237 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002238
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002239 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002240 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002241 for (Receiver receiver : deadReceivers) {
2242 removeUpdatesLocked(receiver);
2243 }
2244 }
2245 if (deadUpdateRecords != null) {
2246 for (UpdateRecord r : deadUpdateRecords) {
2247 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002248 }
Victoria Lease8b38b292012-12-04 15:04:43 -08002249 applyRequirementsLocked(provider);
2250 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002251 }
2252
2253 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08002254 public LocationWorkerHandler(Looper looper) {
2255 super(looper, null, true);
2256 }
2257
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002258 @Override
2259 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002260 switch (msg.what) {
2261 case MSG_LOCATION_CHANGED:
2262 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
2263 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002264 }
2265 }
2266 }
2267
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002268 private boolean isMockProvider(String provider) {
2269 synchronized (mLock) {
2270 return mMockProviders.containsKey(provider);
2271 }
2272 }
2273
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002274 private void handleLocationChanged(Location location, boolean passive) {
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002275 // create a working copy of the incoming Location so that the service can modify it without
2276 // disturbing the caller's copy
2277 Location myLocation = new Location(location);
2278 String provider = myLocation.getProvider();
2279
2280 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
2281 // bit if location did not come from a mock provider because passive/fused providers can
2282 // forward locations from mock providers, and should not grant them legitimacy in doing so.
2283 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
2284 myLocation.setIsFromMockProvider(true);
2285 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08002286
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002287 synchronized (mLock) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08002288 if (isAllowedByCurrentUserSettingsLocked(provider)) {
2289 if (!passive) {
2290 // notify passive provider of the new location
2291 mPassiveProvider.updateLocation(myLocation);
2292 }
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002293 handleLocationChangedLocked(myLocation, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002294 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002295 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002296 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002297
Mike Lockwoode97ae402010-09-29 15:23:46 -04002298 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
2299 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002300 public void onPackageDisappeared(String packageName, int reason) {
2301 // remove all receivers associated with this package name
2302 synchronized (mLock) {
2303 ArrayList<Receiver> deadReceivers = null;
2304
2305 for (Receiver receiver : mReceivers.values()) {
2306 if (receiver.mPackageName.equals(packageName)) {
2307 if (deadReceivers == null) {
2308 deadReceivers = new ArrayList<Receiver>();
2309 }
2310 deadReceivers.add(receiver);
2311 }
2312 }
2313
2314 // perform removal outside of mReceivers loop
2315 if (deadReceivers != null) {
2316 for (Receiver receiver : deadReceivers) {
2317 removeUpdatesLocked(receiver);
2318 }
2319 }
2320 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002321 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04002322 };
2323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002324 // Geocoder
2325
Nick Pellye0fd6932012-07-11 10:26:13 -07002326 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04002327 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07002328 return mGeocodeProvider != null;
2329 }
2330
Nick Pellye0fd6932012-07-11 10:26:13 -07002331 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002332 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05002333 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04002334 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002335 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
2336 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002337 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002338 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002339 }
2340
Mike Lockwooda55c3212009-04-15 11:10:11 -04002341
Nick Pellye0fd6932012-07-11 10:26:13 -07002342 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002343 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04002344 double lowerLeftLatitude, double lowerLeftLongitude,
2345 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05002346 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04002347
2348 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002349 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
2350 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
2351 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002352 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002353 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002354 }
2355
2356 // Mock Providers
2357
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002358 private void checkMockPermissionsSafe() {
2359 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
2360 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
2361 if (!allowMocks) {
2362 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
2363 }
2364
2365 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
David Christie2ff96af2014-01-30 16:09:37 -08002366 PackageManager.PERMISSION_GRANTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002367 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07002368 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002369 }
2370
Nick Pellye0fd6932012-07-11 10:26:13 -07002371 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002372 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002373 checkMockPermissionsSafe();
2374
Mike Lockwooda4903f22010-02-17 06:42:23 -05002375 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
2376 throw new IllegalArgumentException("Cannot mock the passive location provider");
2377 }
2378
Mike Lockwood86328a92009-10-23 08:38:25 -04002379 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002380 synchronized (mLock) {
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002381 // remove the real provider if we are replacing GPS or network provider
2382 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07002383 || LocationManager.NETWORK_PROVIDER.equals(name)
2384 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002385 LocationProviderInterface p = mProvidersByName.get(name);
2386 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002387 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002388 }
2389 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09002390 addTestProviderLocked(name, properties);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002391 updateProvidersLocked();
2392 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002393 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002394 }
2395
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09002396 private void addTestProviderLocked(String name, ProviderProperties properties) {
2397 if (mProvidersByName.get(name) != null) {
2398 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2399 }
2400 MockProvider provider = new MockProvider(name, this, properties);
2401 addProviderLocked(provider);
2402 mMockProviders.put(name, provider);
2403 mLastLocation.put(name, null);
2404 mLastLocationCoarseInterval.put(name, null);
2405 }
2406
Nick Pellye0fd6932012-07-11 10:26:13 -07002407 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002408 public void removeTestProvider(String provider) {
2409 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002410 synchronized (mLock) {
Tom O'Neill07ee5d12014-03-03 17:48:35 -08002411
2412 // These methods can't be called after removing the test provider, so first make sure
Tom O'Neillfe6d3c52014-03-04 08:26:17 -08002413 // we don't leave anything dangling.
Tom O'Neill07ee5d12014-03-03 17:48:35 -08002414 clearTestProviderEnabled(provider);
2415 clearTestProviderLocation(provider);
2416 clearTestProviderStatus(provider);
2417
You Kima6d0b6f2012-10-28 03:58:44 +09002418 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002419 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002420 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2421 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002422 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002423 removeProviderLocked(mProvidersByName.get(provider));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002424
2425 // reinstate real provider if available
2426 LocationProviderInterface realProvider = mRealProviders.get(provider);
2427 if (realProvider != null) {
2428 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002429 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002430 mLastLocation.put(provider, null);
David Christie1b9b7b12013-04-15 15:31:11 -07002431 mLastLocationCoarseInterval.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002432 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002433 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002434 }
2435 }
2436
Nick Pellye0fd6932012-07-11 10:26:13 -07002437 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002438 public void setTestProviderLocation(String provider, Location loc) {
2439 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002440 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002441 MockProvider mockProvider = mMockProviders.get(provider);
2442 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002443 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2444 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04002445 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2446 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002447 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04002448 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002449 }
2450 }
2451
Nick Pellye0fd6932012-07-11 10:26:13 -07002452 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002453 public void clearTestProviderLocation(String provider) {
2454 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002455 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002456 MockProvider mockProvider = mMockProviders.get(provider);
2457 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002458 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2459 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002460 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002461 }
2462 }
2463
Nick Pellye0fd6932012-07-11 10:26:13 -07002464 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002465 public void setTestProviderEnabled(String provider, boolean enabled) {
2466 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002467 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002468 MockProvider mockProvider = mMockProviders.get(provider);
2469 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002470 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2471 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002472 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002473 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002474 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002475 mEnabledProviders.add(provider);
2476 mDisabledProviders.remove(provider);
2477 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002478 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002479 mEnabledProviders.remove(provider);
2480 mDisabledProviders.add(provider);
2481 }
2482 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002483 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002484 }
2485 }
2486
Nick Pellye0fd6932012-07-11 10:26:13 -07002487 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002488 public void clearTestProviderEnabled(String provider) {
2489 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002490 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002491 MockProvider mockProvider = mMockProviders.get(provider);
2492 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002493 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2494 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002495 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002496 mEnabledProviders.remove(provider);
2497 mDisabledProviders.remove(provider);
2498 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002499 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002500 }
2501 }
2502
Nick Pellye0fd6932012-07-11 10:26:13 -07002503 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002504 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2505 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002506 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002507 MockProvider mockProvider = mMockProviders.get(provider);
2508 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002509 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2510 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002511 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002512 }
2513 }
2514
Nick Pellye0fd6932012-07-11 10:26:13 -07002515 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002516 public void clearTestProviderStatus(String provider) {
2517 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002518 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002519 MockProvider mockProvider = mMockProviders.get(provider);
2520 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002521 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2522 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002523 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002524 }
2525 }
2526
2527 private void log(String log) {
2528 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002529 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002530 }
2531 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002532
2533 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002534 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2535 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2536 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04002537 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002538 + Binder.getCallingPid()
2539 + ", uid=" + Binder.getCallingUid());
2540 return;
2541 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002542
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002543 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002544 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002545 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002546 for (Receiver receiver : mReceivers.values()) {
2547 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002548 }
David Christie2ff96af2014-01-30 16:09:37 -08002549 pw.println(" Active Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002550 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2551 pw.println(" " + entry.getKey() + ":");
2552 for (UpdateRecord record : entry.getValue()) {
2553 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002554 }
2555 }
David Christie2ff96af2014-01-30 16:09:37 -08002556 pw.println(" Historical Records by Provider:");
2557 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
2558 : mRequestStatistics.statistics.entrySet()) {
2559 PackageProviderKey key = entry.getKey();
2560 PackageStatistics stats = entry.getValue();
2561 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
2562 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002563 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002564 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2565 String provider = entry.getKey();
2566 Location location = entry.getValue();
2567 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002568 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002569
David Christie1b9b7b12013-04-15 15:31:11 -07002570 pw.println(" Last Known Locations Coarse Intervals:");
2571 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
2572 String provider = entry.getKey();
2573 Location location = entry.getValue();
2574 pw.println(" " + provider + ": " + location);
2575 }
2576
Nick Pellye0fd6932012-07-11 10:26:13 -07002577 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002578
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002579 if (mEnabledProviders.size() > 0) {
2580 pw.println(" Enabled Providers:");
2581 for (String i : mEnabledProviders) {
2582 pw.println(" " + i);
2583 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002585 }
2586 if (mDisabledProviders.size() > 0) {
2587 pw.println(" Disabled Providers:");
2588 for (String i : mDisabledProviders) {
2589 pw.println(" " + i);
2590 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002591 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002592 pw.append(" ");
2593 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002594 if (mMockProviders.size() > 0) {
2595 pw.println(" Mock Providers:");
2596 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002597 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002598 }
2599 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002600
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002601 pw.append(" fudger: ");
2602 mLocationFudger.dump(fd, pw, args);
2603
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002604 if (args.length > 0 && "short".equals(args[0])) {
2605 return;
2606 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002607 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002608 pw.print(provider.getName() + " Internal State");
2609 if (provider instanceof LocationProviderProxy) {
2610 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2611 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002612 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002613 pw.println(":");
2614 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002615 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002616 }
2617 }
2618}