LocationManagerService.java revision 1332b53522e281012fefb34bfbcc68a03028f516
1/* 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 19import android.app.PendingIntent; 20import android.content.ContentQueryMap; 21import android.content.ContentResolver; 22import android.content.Context; 23import android.content.Intent; 24import android.content.IntentFilter; 25import android.content.pm.ApplicationInfo; 26import android.content.pm.PackageManager; 27import android.content.pm.PackageManager.NameNotFoundException; 28import android.content.res.Resources; 29import android.database.Cursor; 30import android.location.Address; 31import android.location.Criteria; 32import android.location.GeocoderParams; 33import android.location.Geofence; 34import android.location.IGpsStatusListener; 35import android.location.IGpsStatusProvider; 36import android.location.ILocationListener; 37import android.location.ILocationManager; 38import android.location.INetInitiatedListener; 39import android.location.Location; 40import android.location.LocationManager; 41import android.location.LocationProvider; 42import android.location.LocationRequest; 43import android.net.ConnectivityManager; 44import android.os.Binder; 45import android.os.Bundle; 46import android.os.Handler; 47import android.os.IBinder; 48import android.os.Looper; 49import android.os.Message; 50import android.os.PowerManager; 51import android.os.Process; 52import android.os.RemoteException; 53import android.os.SystemClock; 54import android.os.WorkSource; 55import android.provider.Settings; 56import android.provider.Settings.NameValueTable; 57import android.util.Log; 58import android.util.Slog; 59 60import com.android.internal.content.PackageMonitor; 61import com.android.internal.location.ProviderProperties; 62import com.android.internal.location.ProviderRequest; 63import com.android.server.location.GeocoderProxy; 64import com.android.server.location.GeofenceManager; 65import com.android.server.location.GpsLocationProvider; 66import com.android.server.location.LocationBlacklist; 67import com.android.server.location.LocationFudger; 68import com.android.server.location.LocationProviderInterface; 69import com.android.server.location.LocationProviderProxy; 70import com.android.server.location.MockProvider; 71import com.android.server.location.PassiveProvider; 72 73import java.io.FileDescriptor; 74import java.io.PrintWriter; 75import java.util.ArrayList; 76import java.util.Arrays; 77import java.util.HashMap; 78import java.util.HashSet; 79import java.util.List; 80import java.util.Map; 81import java.util.Observable; 82import java.util.Observer; 83import java.util.Set; 84 85/** 86 * The service class that manages LocationProviders and issues location 87 * updates and alerts. 88 */ 89public class LocationManagerService extends ILocationManager.Stub implements Observer, Runnable { 90 private static final String TAG = "LocationManagerService"; 91 public static final boolean D = false; 92 93 private static final String WAKELOCK_KEY = TAG; 94 private static final String THREAD_NAME = TAG; 95 96 private static final String ACCESS_FINE_LOCATION = 97 android.Manifest.permission.ACCESS_FINE_LOCATION; 98 private static final String ACCESS_COARSE_LOCATION = 99 android.Manifest.permission.ACCESS_COARSE_LOCATION; 100 private static final String ACCESS_MOCK_LOCATION = 101 android.Manifest.permission.ACCESS_MOCK_LOCATION; 102 private static final String ACCESS_LOCATION_EXTRA_COMMANDS = 103 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS; 104 private static final String INSTALL_LOCATION_PROVIDER = 105 android.Manifest.permission.INSTALL_LOCATION_PROVIDER; 106 107 private static final String NETWORK_LOCATION_SERVICE_ACTION = 108 "com.android.location.service.v2.NetworkLocationProvider"; 109 private static final String FUSED_LOCATION_SERVICE_ACTION = 110 "com.android.location.service.FusedLocationProvider"; 111 112 private static final int MSG_LOCATION_CHANGED = 1; 113 114 // Location Providers may sometimes deliver location updates 115 // slightly faster that requested - provide grace period so 116 // we don't unnecessarily filter events that are otherwise on 117 // time 118 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100; 119 120 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest(); 121 122 private final Context mContext; 123 124 // used internally for synchronization 125 private final Object mLock = new Object(); 126 127 // --- fields below are final after init() --- 128 private LocationFudger mLocationFudger; 129 private GeofenceManager mGeofenceManager; 130 private PowerManager.WakeLock mWakeLock; 131 private PackageManager mPackageManager; 132 private GeocoderProxy mGeocodeProvider; 133 private IGpsStatusProvider mGpsStatusProvider; 134 private INetInitiatedListener mNetInitiatedListener; 135 private LocationWorkerHandler mLocationHandler; 136 private PassiveProvider mPassiveProvider; // track passive provider for special cases 137 private LocationBlacklist mBlacklist; 138 139 // --- fields below are protected by mWakeLock --- 140 private int mPendingBroadcasts; 141 142 // --- fields below are protected by mLock --- 143 // Set of providers that are explicitly enabled 144 private final Set<String> mEnabledProviders = new HashSet<String>(); 145 146 // Set of providers that are explicitly disabled 147 private final Set<String> mDisabledProviders = new HashSet<String>(); 148 149 // Mock (test) providers 150 private final HashMap<String, MockProvider> mMockProviders = 151 new HashMap<String, MockProvider>(); 152 153 // all receivers 154 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>(); 155 156 // currently installed providers (with mocks replacing real providers) 157 private final ArrayList<LocationProviderInterface> mProviders = 158 new ArrayList<LocationProviderInterface>(); 159 160 // real providers, saved here when mocked out 161 private final HashMap<String, LocationProviderInterface> mRealProviders = 162 new HashMap<String, LocationProviderInterface>(); 163 164 // mapping from provider name to provider 165 private final HashMap<String, LocationProviderInterface> mProvidersByName = 166 new HashMap<String, LocationProviderInterface>(); 167 168 // mapping from provider name to all its UpdateRecords 169 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider = 170 new HashMap<String, ArrayList<UpdateRecord>>(); 171 172 // mapping from provider name to last known location 173 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>(); 174 175 // all providers that operate over proxy, for authorizing incoming location 176 private final ArrayList<LocationProviderProxy> mProxyProviders = 177 new ArrayList<LocationProviderProxy>(); 178 179 public LocationManagerService(Context context) { 180 super(); 181 mContext = context; 182 183 if (D) Log.d(TAG, "Constructed"); 184 185 // most startup is deferred until systemReady() 186 } 187 188 public void systemReady() { 189 Thread thread = new Thread(null, this, THREAD_NAME); 190 thread.start(); 191 } 192 193 @Override 194 public void run() { 195 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 196 Looper.prepare(); 197 mLocationHandler = new LocationWorkerHandler(); 198 init(); 199 Looper.loop(); 200 } 201 202 private void init() { 203 if (D) Log.d(TAG, "init()"); 204 205 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 206 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); 207 mPackageManager = mContext.getPackageManager(); 208 209 synchronized (mLock) { 210 loadProvidersLocked(); 211 } 212 mBlacklist = new LocationBlacklist(mContext, mLocationHandler); 213 mBlacklist.init(); 214 mGeofenceManager = new GeofenceManager(mContext, mBlacklist); 215 mLocationFudger = new LocationFudger(); 216 217 // Register for Network (Wifi or Mobile) updates 218 IntentFilter filter = new IntentFilter(); 219 filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 220 221 // listen for settings changes 222 ContentResolver resolver = mContext.getContentResolver(); 223 Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null, 224 "(" + NameValueTable.NAME + "=?)", 225 new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED}, null); 226 ContentQueryMap query = new ContentQueryMap(settingsCursor, NameValueTable.NAME, true, 227 mLocationHandler); 228 settingsCursor.close(); 229 query.addObserver(this); 230 mPackageMonitor.register(mContext, Looper.myLooper(), true); 231 } 232 233 private void loadProvidersLocked() { 234 if (GpsLocationProvider.isSupported()) { 235 // Create a gps location provider 236 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this); 237 mGpsStatusProvider = gpsProvider.getGpsStatusProvider(); 238 mNetInitiatedListener = gpsProvider.getNetInitiatedListener(); 239 addProviderLocked(gpsProvider); 240 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider); 241 } 242 243 // create a passive location provider, which is always enabled 244 PassiveProvider passiveProvider = new PassiveProvider(this); 245 addProviderLocked(passiveProvider); 246 mEnabledProviders.add(passiveProvider.getName()); 247 mPassiveProvider = passiveProvider; 248 249 /* 250 Load package name(s) containing location provider support. 251 These packages can contain services implementing location providers: 252 Geocoder Provider, Network Location Provider, and 253 Fused Location Provider. They will each be searched for 254 service components implementing these providers. 255 The location framework also has support for installation 256 of new location providers at run-time. The new package does not 257 have to be explicitly listed here, however it must have a signature 258 that matches the signature of at least one package on this list. 259 */ 260 Resources resources = mContext.getResources(); 261 ArrayList<String> providerPackageNames = new ArrayList<String>(); 262 String[] pkgs1 = resources.getStringArray( 263 com.android.internal.R.array.config_locationProviderPackageNames); 264 String[] pkgs2 = resources.getStringArray( 265 com.android.internal.R.array.config_overlay_locationProviderPackageNames); 266 if (D) Log.d(TAG, "built-in location providers: " + Arrays.toString(pkgs1)); 267 if (D) Log.d(TAG, "overlay location providers: " + Arrays.toString(pkgs2)); 268 if (pkgs1 != null) providerPackageNames.addAll(Arrays.asList(pkgs1)); 269 if (pkgs2 != null) providerPackageNames.addAll(Arrays.asList(pkgs2)); 270 271 // bind to network provider 272 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind( 273 mContext, 274 LocationManager.NETWORK_PROVIDER, 275 NETWORK_LOCATION_SERVICE_ACTION, 276 providerPackageNames, mLocationHandler); 277 if (networkProvider != null) { 278 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider); 279 mProxyProviders.add(networkProvider); 280 addProviderLocked(networkProvider); 281 } else { 282 Slog.w(TAG, "no network location provider found"); 283 } 284 285 // bind to fused provider 286 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind( 287 mContext, 288 LocationManager.FUSED_PROVIDER, 289 FUSED_LOCATION_SERVICE_ACTION, 290 providerPackageNames, mLocationHandler); 291 if (fusedLocationProvider != null) { 292 addProviderLocked(fusedLocationProvider); 293 mProxyProviders.add(fusedLocationProvider); 294 mEnabledProviders.add(fusedLocationProvider.getName()); 295 } else { 296 Slog.e(TAG, "no fused location provider found", 297 new IllegalStateException("Location service needs a fused location provider")); 298 } 299 300 // bind to geocoder provider 301 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames); 302 if (mGeocodeProvider == null) { 303 Slog.e(TAG, "no geocoder provider found"); 304 } 305 306 updateProvidersLocked(); 307 } 308 309 /** 310 * A wrapper class holding either an ILocationListener or a PendingIntent to receive 311 * location updates. 312 */ 313 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished { 314 final int mUid; // uid of receiver 315 final int mPid; // pid of receiver 316 final String mPackageName; // package name of receiver 317 final String mPermission; // best permission that receiver has 318 319 final ILocationListener mListener; 320 final PendingIntent mPendingIntent; 321 final Object mKey; 322 323 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>(); 324 325 int mPendingBroadcasts; 326 327 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid, 328 String packageName) { 329 mListener = listener; 330 mPendingIntent = intent; 331 if (listener != null) { 332 mKey = listener.asBinder(); 333 } else { 334 mKey = intent; 335 } 336 mPermission = checkPermission(); 337 mUid = uid; 338 mPid = pid; 339 mPackageName = packageName; 340 } 341 342 @Override 343 public boolean equals(Object otherObj) { 344 if (otherObj instanceof Receiver) { 345 return mKey.equals(((Receiver)otherObj).mKey); 346 } 347 return false; 348 } 349 350 @Override 351 public int hashCode() { 352 return mKey.hashCode(); 353 } 354 355 @Override 356 public String toString() { 357 StringBuilder s = new StringBuilder(); 358 s.append("Reciever["); 359 s.append(Integer.toHexString(System.identityHashCode(this))); 360 if (mListener != null) { 361 s.append(" listener"); 362 } else { 363 s.append(" intent"); 364 } 365 for (String p : mUpdateRecords.keySet()) { 366 s.append(" ").append(mUpdateRecords.get(p).toString()); 367 } 368 s.append("]"); 369 return s.toString(); 370 } 371 372 public boolean isListener() { 373 return mListener != null; 374 } 375 376 public boolean isPendingIntent() { 377 return mPendingIntent != null; 378 } 379 380 public ILocationListener getListener() { 381 if (mListener != null) { 382 return mListener; 383 } 384 throw new IllegalStateException("Request for non-existent listener"); 385 } 386 387 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) { 388 if (mListener != null) { 389 try { 390 synchronized (this) { 391 // synchronize to ensure incrementPendingBroadcastsLocked() 392 // is called before decrementPendingBroadcasts() 393 mListener.onStatusChanged(provider, status, extras); 394 // call this after broadcasting so we do not increment 395 // if we throw an exeption. 396 incrementPendingBroadcastsLocked(); 397 } 398 } catch (RemoteException e) { 399 return false; 400 } 401 } else { 402 Intent statusChanged = new Intent(); 403 statusChanged.putExtras(extras); 404 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status); 405 try { 406 synchronized (this) { 407 // synchronize to ensure incrementPendingBroadcastsLocked() 408 // is called before decrementPendingBroadcasts() 409 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler, 410 mPermission); 411 // call this after broadcasting so we do not increment 412 // if we throw an exeption. 413 incrementPendingBroadcastsLocked(); 414 } 415 } catch (PendingIntent.CanceledException e) { 416 return false; 417 } 418 } 419 return true; 420 } 421 422 public boolean callLocationChangedLocked(Location location) { 423 if (mListener != null) { 424 try { 425 synchronized (this) { 426 // synchronize to ensure incrementPendingBroadcastsLocked() 427 // is called before decrementPendingBroadcasts() 428 mListener.onLocationChanged(location); 429 // call this after broadcasting so we do not increment 430 // if we throw an exeption. 431 incrementPendingBroadcastsLocked(); 432 } 433 } catch (RemoteException e) { 434 return false; 435 } 436 } else { 437 Intent locationChanged = new Intent(); 438 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location); 439 try { 440 synchronized (this) { 441 // synchronize to ensure incrementPendingBroadcastsLocked() 442 // is called before decrementPendingBroadcasts() 443 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler, 444 mPermission); 445 // call this after broadcasting so we do not increment 446 // if we throw an exeption. 447 incrementPendingBroadcastsLocked(); 448 } 449 } catch (PendingIntent.CanceledException e) { 450 return false; 451 } 452 } 453 return true; 454 } 455 456 public boolean callProviderEnabledLocked(String provider, boolean enabled) { 457 if (mListener != null) { 458 try { 459 synchronized (this) { 460 // synchronize to ensure incrementPendingBroadcastsLocked() 461 // is called before decrementPendingBroadcasts() 462 if (enabled) { 463 mListener.onProviderEnabled(provider); 464 } else { 465 mListener.onProviderDisabled(provider); 466 } 467 // call this after broadcasting so we do not increment 468 // if we throw an exeption. 469 incrementPendingBroadcastsLocked(); 470 } 471 } catch (RemoteException e) { 472 return false; 473 } 474 } else { 475 Intent providerIntent = new Intent(); 476 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled); 477 try { 478 synchronized (this) { 479 // synchronize to ensure incrementPendingBroadcastsLocked() 480 // is called before decrementPendingBroadcasts() 481 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler, 482 mPermission); 483 // call this after broadcasting so we do not increment 484 // if we throw an exeption. 485 incrementPendingBroadcastsLocked(); 486 } 487 } catch (PendingIntent.CanceledException e) { 488 return false; 489 } 490 } 491 return true; 492 } 493 494 @Override 495 public void binderDied() { 496 if (D) Log.d(TAG, "Location listener died"); 497 498 synchronized (mLock) { 499 removeUpdatesLocked(this); 500 } 501 synchronized (this) { 502 if (mPendingBroadcasts > 0) { 503 LocationManagerService.this.decrementPendingBroadcasts(); 504 mPendingBroadcasts = 0; 505 } 506 } 507 } 508 509 @Override 510 public void onSendFinished(PendingIntent pendingIntent, Intent intent, 511 int resultCode, String resultData, Bundle resultExtras) { 512 synchronized (this) { 513 decrementPendingBroadcastsLocked(); 514 } 515 } 516 517 // this must be called while synchronized by caller in a synchronized block 518 // containing the sending of the broadcaset 519 private void incrementPendingBroadcastsLocked() { 520 if (mPendingBroadcasts++ == 0) { 521 LocationManagerService.this.incrementPendingBroadcasts(); 522 } 523 } 524 525 private void decrementPendingBroadcastsLocked() { 526 if (--mPendingBroadcasts == 0) { 527 LocationManagerService.this.decrementPendingBroadcasts(); 528 } 529 } 530 } 531 532 @Override 533 public void locationCallbackFinished(ILocationListener listener) { 534 //Do not use getReceiver here as that will add the ILocationListener to 535 //the receiver list if it is not found. If it is not found then the 536 //LocationListener was removed when it had a pending broadcast and should 537 //not be added back. 538 IBinder binder = listener.asBinder(); 539 Receiver receiver = mReceivers.get(binder); 540 if (receiver != null) { 541 synchronized (receiver) { 542 // so wakelock calls will succeed 543 long identity = Binder.clearCallingIdentity(); 544 receiver.decrementPendingBroadcastsLocked(); 545 Binder.restoreCallingIdentity(identity); 546 } 547 } 548 } 549 550 /** Settings Observer callback */ 551 @Override 552 public void update(Observable o, Object arg) { 553 synchronized (mLock) { 554 updateProvidersLocked(); 555 } 556 } 557 558 private void addProviderLocked(LocationProviderInterface provider) { 559 mProviders.add(provider); 560 mProvidersByName.put(provider.getName(), provider); 561 } 562 563 private void removeProviderLocked(LocationProviderInterface provider) { 564 provider.disable(); 565 mProviders.remove(provider); 566 mProvidersByName.remove(provider.getName()); 567 } 568 569 570 private boolean isAllowedBySettingsLocked(String provider) { 571 if (mEnabledProviders.contains(provider)) { 572 return true; 573 } 574 if (mDisabledProviders.contains(provider)) { 575 return false; 576 } 577 // Use system settings 578 ContentResolver resolver = mContext.getContentResolver(); 579 580 return Settings.Secure.isLocationProviderEnabled(resolver, provider); 581 } 582 583 /** 584 * Throw SecurityException if caller has neither COARSE or FINE. 585 * Otherwise, return the best permission. 586 */ 587 private String checkPermission() { 588 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) == 589 PackageManager.PERMISSION_GRANTED) { 590 return ACCESS_FINE_LOCATION; 591 } else if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) == 592 PackageManager.PERMISSION_GRANTED) { 593 return ACCESS_COARSE_LOCATION; 594 } 595 596 throw new SecurityException("Location requires either ACCESS_COARSE_LOCATION or" + 597 "ACCESS_FINE_LOCATION permission"); 598 } 599 600 /** 601 * Returns all providers by name, including passive, but excluding 602 * fused. 603 */ 604 @Override 605 public List<String> getAllProviders() { 606 checkPermission(); 607 608 ArrayList<String> out; 609 synchronized (mLock) { 610 out = new ArrayList<String>(mProviders.size()); 611 for (LocationProviderInterface provider : mProviders) { 612 String name = provider.getName(); 613 if (LocationManager.FUSED_PROVIDER.equals(name)) { 614 continue; 615 } 616 out.add(name); 617 } 618 } 619 620 if (D) Log.d(TAG, "getAllProviders()=" + out); 621 return out; 622 } 623 624 /** 625 * Return all providers by name, that match criteria and are optionally 626 * enabled. 627 * Can return passive provider, but never returns fused provider. 628 */ 629 @Override 630 public List<String> getProviders(Criteria criteria, boolean enabledOnly) { 631 checkPermission(); 632 633 ArrayList<String> out; 634 synchronized (mLock) { 635 out = new ArrayList<String>(mProviders.size()); 636 for (LocationProviderInterface provider : mProviders) { 637 String name = provider.getName(); 638 if (LocationManager.FUSED_PROVIDER.equals(name)) { 639 continue; 640 } 641 if (enabledOnly && !isAllowedBySettingsLocked(name)) { 642 continue; 643 } 644 if (criteria != null && !LocationProvider.propertiesMeetCriteria( 645 name, provider.getProperties(), criteria)) { 646 continue; 647 } 648 out.add(name); 649 } 650 } 651 652 if (D) Log.d(TAG, "getProviders()=" + out); 653 return out; 654 } 655 656 /** 657 * Return the name of the best provider given a Criteria object. 658 * This method has been deprecated from the public API, 659 * and the whole LoactionProvider (including #meetsCriteria) 660 * has been deprecated as well. So this method now uses 661 * some simplified logic. 662 */ 663 @Override 664 public String getBestProvider(Criteria criteria, boolean enabledOnly) { 665 String result = null; 666 checkPermission(); 667 668 List<String> providers = getProviders(criteria, enabledOnly); 669 if (providers.size() < 1) { 670 result = pickBest(providers); 671 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result); 672 return result; 673 } 674 providers = getProviders(null, enabledOnly); 675 if (providers.size() >= 1) { 676 result = pickBest(providers); 677 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result); 678 return result; 679 } 680 681 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result); 682 return null; 683 } 684 685 private String pickBest(List<String> providers) { 686 if (providers.contains(LocationManager.NETWORK_PROVIDER)) { 687 return LocationManager.NETWORK_PROVIDER; 688 } else if (providers.contains(LocationManager.GPS_PROVIDER)) { 689 return LocationManager.GPS_PROVIDER; 690 } else { 691 return providers.get(0); 692 } 693 } 694 695 @Override 696 public boolean providerMeetsCriteria(String provider, Criteria criteria) { 697 checkPermission(); 698 699 LocationProviderInterface p = mProvidersByName.get(provider); 700 if (p == null) { 701 throw new IllegalArgumentException("provider=" + provider); 702 } 703 704 boolean result = LocationProvider.propertiesMeetCriteria( 705 p.getName(), p.getProperties(), criteria); 706 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result); 707 return result; 708 } 709 710 private void updateProvidersLocked() { 711 boolean changesMade = false; 712 for (int i = mProviders.size() - 1; i >= 0; i--) { 713 LocationProviderInterface p = mProviders.get(i); 714 boolean isEnabled = p.isEnabled(); 715 String name = p.getName(); 716 boolean shouldBeEnabled = isAllowedBySettingsLocked(name); 717 if (isEnabled && !shouldBeEnabled) { 718 updateProviderListenersLocked(name, false); 719 changesMade = true; 720 } else if (!isEnabled && shouldBeEnabled) { 721 updateProviderListenersLocked(name, true); 722 changesMade = true; 723 } 724 } 725 if (changesMade) { 726 mContext.sendBroadcast(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION)); 727 } 728 } 729 730 private void updateProviderListenersLocked(String provider, boolean enabled) { 731 int listeners = 0; 732 733 LocationProviderInterface p = mProvidersByName.get(provider); 734 if (p == null) return; 735 736 ArrayList<Receiver> deadReceivers = null; 737 738 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 739 if (records != null) { 740 final int N = records.size(); 741 for (int i = 0; i < N; i++) { 742 UpdateRecord record = records.get(i); 743 // Sends a notification message to the receiver 744 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) { 745 if (deadReceivers == null) { 746 deadReceivers = new ArrayList<Receiver>(); 747 } 748 deadReceivers.add(record.mReceiver); 749 } 750 listeners++; 751 } 752 } 753 754 if (deadReceivers != null) { 755 for (int i = deadReceivers.size() - 1; i >= 0; i--) { 756 removeUpdatesLocked(deadReceivers.get(i)); 757 } 758 } 759 760 if (enabled) { 761 p.enable(); 762 if (listeners > 0) { 763 applyRequirementsLocked(provider); 764 } 765 } else { 766 p.disable(); 767 } 768 } 769 770 private void applyRequirementsLocked(String provider) { 771 LocationProviderInterface p = mProvidersByName.get(provider); 772 if (p == null) return; 773 774 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 775 WorkSource worksource = new WorkSource(); 776 ProviderRequest providerRequest = new ProviderRequest(); 777 778 if (records != null) { 779 for (UpdateRecord record : records) { 780 LocationRequest locationRequest = record.mRequest; 781 782 providerRequest.locationRequests.add(locationRequest); 783 if (locationRequest.getInterval() < providerRequest.interval) { 784 providerRequest.reportLocation = true; 785 providerRequest.interval = locationRequest.getInterval(); 786 } 787 } 788 789 if (providerRequest.reportLocation) { 790 // calculate who to blame for power 791 // This is somewhat arbitrary. We pick a threshold interval 792 // that is slightly higher that the minimum interval, and 793 // spread the blame across all applications with a request 794 // under that threshold. 795 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2; 796 for (UpdateRecord record : records) { 797 LocationRequest locationRequest = record.mRequest; 798 if (locationRequest.getInterval() <= thresholdInterval) { 799 worksource.add(record.mReceiver.mUid); 800 } 801 } 802 } 803 } 804 805 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest); 806 p.setRequest(providerRequest, worksource); 807 } 808 809 private class UpdateRecord { 810 final String mProvider; 811 final LocationRequest mRequest; 812 final Receiver mReceiver; 813 Location mLastFixBroadcast; 814 long mLastStatusBroadcast; 815 816 /** 817 * Note: must be constructed with lock held. 818 */ 819 UpdateRecord(String provider, LocationRequest request, Receiver receiver) { 820 mProvider = provider; 821 mRequest = request; 822 mReceiver = receiver; 823 824 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 825 if (records == null) { 826 records = new ArrayList<UpdateRecord>(); 827 mRecordsByProvider.put(provider, records); 828 } 829 if (!records.contains(this)) { 830 records.add(this); 831 } 832 } 833 834 /** 835 * Method to be called when a record will no longer be used. Calling this multiple times 836 * must have the same effect as calling it once. 837 */ 838 void disposeLocked(boolean removeReceiver) { 839 // remove from mRecordsByProvider 840 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider); 841 if (globalRecords != null) { 842 globalRecords.remove(this); 843 } 844 845 if (!removeReceiver) return; // the caller will handle the rest 846 847 // remove from Receiver#mUpdateRecords 848 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords; 849 if (receiverRecords != null) { 850 receiverRecords.remove(this.mProvider); 851 852 // and also remove the Receiver if it has no more update records 853 if (removeReceiver && receiverRecords.size() == 0) { 854 removeUpdatesLocked(mReceiver); 855 } 856 } 857 } 858 859 @Override 860 public String toString() { 861 StringBuilder s = new StringBuilder(); 862 s.append("UpdateRecord["); 863 s.append(mProvider); 864 s.append(' ').append(mReceiver.mPackageName).append('('); 865 s.append(mReceiver.mUid).append(')'); 866 s.append(' ').append(mRequest); 867 s.append(']'); 868 return s.toString(); 869 } 870 } 871 872 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) { 873 IBinder binder = listener.asBinder(); 874 Receiver receiver = mReceivers.get(binder); 875 if (receiver == null) { 876 receiver = new Receiver(listener, null, pid, uid, packageName); 877 mReceivers.put(binder, receiver); 878 879 try { 880 receiver.getListener().asBinder().linkToDeath(receiver, 0); 881 } catch (RemoteException e) { 882 Slog.e(TAG, "linkToDeath failed:", e); 883 return null; 884 } 885 } 886 return receiver; 887 } 888 889 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) { 890 Receiver receiver = mReceivers.get(intent); 891 if (receiver == null) { 892 receiver = new Receiver(null, intent, pid, uid, packageName); 893 mReceivers.put(intent, receiver); 894 } 895 return receiver; 896 } 897 898 private String checkPermissionAndRequest(LocationRequest request) { 899 String perm = checkPermission(); 900 901 if (ACCESS_COARSE_LOCATION.equals(perm)) { 902 switch (request.getQuality()) { 903 case LocationRequest.ACCURACY_FINE: 904 request.setQuality(LocationRequest.ACCURACY_BLOCK); 905 break; 906 case LocationRequest.POWER_HIGH: 907 request.setQuality(LocationRequest.POWER_LOW); 908 break; 909 } 910 // throttle 911 if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) { 912 request.setInterval(LocationFudger.FASTEST_INTERVAL_MS); 913 } 914 if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) { 915 request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS); 916 } 917 } 918 // make getFastestInterval() the minimum of interval and fastest interval 919 if (request.getFastestInterval() > request.getInterval()) { 920 request.setFastestInterval(request.getInterval()); 921 } 922 return perm; 923 } 924 925 private void checkPackageName(String packageName) { 926 if (packageName == null) { 927 throw new SecurityException("invalid package name: " + packageName); 928 } 929 int uid = Binder.getCallingUid(); 930 String[] packages = mPackageManager.getPackagesForUid(uid); 931 if (packages == null) { 932 throw new SecurityException("invalid UID " + uid); 933 } 934 for (String pkg : packages) { 935 if (packageName.equals(pkg)) return; 936 } 937 throw new SecurityException("invalid package name: " + packageName); 938 } 939 940 private void checkPendingIntent(PendingIntent intent) { 941 if (intent == null) { 942 throw new IllegalArgumentException("invalid pending intent: " + intent); 943 } 944 } 945 946 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent, 947 int pid, int uid, String packageName) { 948 if (intent == null && listener == null) { 949 throw new IllegalArgumentException("need eiter listener or intent"); 950 } else if (intent != null && listener != null) { 951 throw new IllegalArgumentException("cannot register both listener and intent"); 952 } else if (intent != null) { 953 checkPendingIntent(intent); 954 return getReceiver(intent, pid, uid, packageName); 955 } else { 956 return getReceiver(listener, pid, uid, packageName); 957 } 958 } 959 960 @Override 961 public void requestLocationUpdates(LocationRequest request, ILocationListener listener, 962 PendingIntent intent, String packageName) { 963 if (request == null) request = DEFAULT_LOCATION_REQUEST; 964 checkPackageName(packageName); 965 checkPermissionAndRequest(request); 966 967 final int pid = Binder.getCallingPid(); 968 final int uid = Binder.getCallingUid(); 969 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName); 970 971 // providers may use public location API's, need to clear identity 972 long identity = Binder.clearCallingIdentity(); 973 try { 974 synchronized (mLock) { 975 requestLocationUpdatesLocked(request, recevier, pid, uid, packageName); 976 } 977 } finally { 978 Binder.restoreCallingIdentity(identity); 979 } 980 } 981 982 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver, 983 int pid, int uid, String packageName) { 984 // Figure out the provider. Either its explicitly request (legacy use cases), or 985 // use the fused provider 986 if (request == null) request = DEFAULT_LOCATION_REQUEST; 987 String name = request.getProvider(); 988 if (name == null) name = LocationManager.FUSED_PROVIDER; 989 LocationProviderInterface provider = mProvidersByName.get(name); 990 if (provider == null) { 991 throw new IllegalArgumentException("provider doesn't exisit: " + provider); 992 } 993 994 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " + 995 name + " " + request + " from " + packageName + "(" + uid + ")"); 996 997 UpdateRecord record = new UpdateRecord(name, request, receiver); 998 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record); 999 if (oldRecord != null) { 1000 oldRecord.disposeLocked(false); 1001 } 1002 1003 boolean isProviderEnabled = isAllowedBySettingsLocked(name); 1004 if (isProviderEnabled) { 1005 applyRequirementsLocked(name); 1006 } else { 1007 // Notify the listener that updates are currently disabled 1008 receiver.callProviderEnabledLocked(name, false); 1009 } 1010 } 1011 1012 @Override 1013 public void removeUpdates(ILocationListener listener, PendingIntent intent, 1014 String packageName) { 1015 checkPackageName(packageName); 1016 checkPermission(); 1017 final int pid = Binder.getCallingPid(); 1018 final int uid = Binder.getCallingUid(); 1019 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName); 1020 1021 // providers may use public location API's, need to clear identity 1022 long identity = Binder.clearCallingIdentity(); 1023 try { 1024 synchronized (mLock) { 1025 removeUpdatesLocked(receiver); 1026 } 1027 } finally { 1028 Binder.restoreCallingIdentity(identity); 1029 } 1030 } 1031 1032 private void removeUpdatesLocked(Receiver receiver) { 1033 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver))); 1034 1035 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) { 1036 receiver.getListener().asBinder().unlinkToDeath(receiver, 0); 1037 synchronized (receiver) { 1038 if (receiver.mPendingBroadcasts > 0) { 1039 decrementPendingBroadcasts(); 1040 receiver.mPendingBroadcasts = 0; 1041 } 1042 } 1043 } 1044 1045 // Record which providers were associated with this listener 1046 HashSet<String> providers = new HashSet<String>(); 1047 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords; 1048 if (oldRecords != null) { 1049 // Call dispose() on the obsolete update records. 1050 for (UpdateRecord record : oldRecords.values()) { 1051 record.disposeLocked(false); 1052 } 1053 // Accumulate providers 1054 providers.addAll(oldRecords.keySet()); 1055 } 1056 1057 // update provider 1058 for (String provider : providers) { 1059 // If provider is already disabled, don't need to do anything 1060 if (!isAllowedBySettingsLocked(provider)) { 1061 continue; 1062 } 1063 1064 applyRequirementsLocked(provider); 1065 } 1066 } 1067 1068 @Override 1069 public Location getLastLocation(LocationRequest request, String packageName) { 1070 if (D) Log.d(TAG, "getLastLocation: " + request); 1071 if (request == null) request = DEFAULT_LOCATION_REQUEST; 1072 String perm = checkPermissionAndRequest(request); 1073 checkPackageName(packageName); 1074 1075 if (mBlacklist.isBlacklisted(packageName)) { 1076 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " + 1077 packageName); 1078 return null; 1079 } 1080 1081 synchronized (mLock) { 1082 // Figure out the provider. Either its explicitly request (deprecated API's), 1083 // or use the fused provider 1084 String name = request.getProvider(); 1085 if (name == null) name = LocationManager.FUSED_PROVIDER; 1086 LocationProviderInterface provider = mProvidersByName.get(name); 1087 if (provider == null) return null; 1088 1089 if (!isAllowedBySettingsLocked(name)) return null; 1090 1091 Location location = mLastLocation.get(name); 1092 if (ACCESS_FINE_LOCATION.equals(perm)) { 1093 return location; 1094 } else { 1095 return mLocationFudger.getOrCreate(location); 1096 } 1097 } 1098 } 1099 1100 @Override 1101 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent, 1102 String packageName) { 1103 if (request == null) request = DEFAULT_LOCATION_REQUEST; 1104 checkPermissionAndRequest(request); 1105 checkPendingIntent(intent); 1106 checkPackageName(packageName); 1107 1108 if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent); 1109 1110 // geo-fence manager uses the public location API, need to clear identity 1111 int uid = Binder.getCallingUid(); 1112 long identity = Binder.clearCallingIdentity(); 1113 try { 1114 mGeofenceManager.addFence(request, geofence, intent, uid, packageName); 1115 } finally { 1116 Binder.restoreCallingIdentity(identity); 1117 } 1118 } 1119 1120 @Override 1121 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) { 1122 checkPermission(); 1123 checkPendingIntent(intent); 1124 checkPackageName(packageName); 1125 1126 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent); 1127 1128 // geo-fence manager uses the public location API, need to clear identity 1129 long identity = Binder.clearCallingIdentity(); 1130 try { 1131 mGeofenceManager.removeFence(geofence, intent); 1132 } finally { 1133 Binder.restoreCallingIdentity(identity); 1134 } 1135 } 1136 1137 1138 @Override 1139 public boolean addGpsStatusListener(IGpsStatusListener listener) { 1140 if (mGpsStatusProvider == null) { 1141 return false; 1142 } 1143 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) != 1144 PackageManager.PERMISSION_GRANTED) { 1145 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); 1146 } 1147 1148 try { 1149 mGpsStatusProvider.addGpsStatusListener(listener); 1150 } catch (RemoteException e) { 1151 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e); 1152 return false; 1153 } 1154 return true; 1155 } 1156 1157 @Override 1158 public void removeGpsStatusListener(IGpsStatusListener listener) { 1159 synchronized (mLock) { 1160 try { 1161 mGpsStatusProvider.removeGpsStatusListener(listener); 1162 } catch (Exception e) { 1163 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e); 1164 } 1165 } 1166 } 1167 1168 @Override 1169 public boolean sendExtraCommand(String provider, String command, Bundle extras) { 1170 if (provider == null) { 1171 // throw NullPointerException to remain compatible with previous implementation 1172 throw new NullPointerException(); 1173 } 1174 1175 checkPermission(); 1176 // and check for ACCESS_LOCATION_EXTRA_COMMANDS 1177 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS) 1178 != PackageManager.PERMISSION_GRANTED)) { 1179 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission"); 1180 } 1181 1182 synchronized (mLock) { 1183 LocationProviderInterface p = mProvidersByName.get(provider); 1184 if (p == null) return false; 1185 1186 return p.sendExtraCommand(command, extras); 1187 } 1188 } 1189 1190 @Override 1191 public boolean sendNiResponse(int notifId, int userResponse) { 1192 if (Binder.getCallingUid() != Process.myUid()) { 1193 throw new SecurityException( 1194 "calling sendNiResponse from outside of the system is not allowed"); 1195 } 1196 try { 1197 return mNetInitiatedListener.sendNiResponse(notifId, userResponse); 1198 } catch (RemoteException e) { 1199 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse"); 1200 return false; 1201 } 1202 } 1203 1204 /** 1205 * @return null if the provider does not exist 1206 * @throws SecurityException if the provider is not allowed to be 1207 * accessed by the caller 1208 */ 1209 @Override 1210 public ProviderProperties getProviderProperties(String provider) { 1211 checkPermission(); 1212 1213 LocationProviderInterface p; 1214 synchronized (mLock) { 1215 p = mProvidersByName.get(provider); 1216 } 1217 1218 if (p == null) return null; 1219 return p.getProperties(); 1220 } 1221 1222 @Override 1223 public boolean isProviderEnabled(String provider) { 1224 checkPermission(); 1225 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false; 1226 1227 synchronized (mLock) { 1228 LocationProviderInterface p = mProvidersByName.get(provider); 1229 if (p == null) return false; 1230 1231 return isAllowedBySettingsLocked(provider); 1232 } 1233 } 1234 1235 private void checkCallerIsProvider() { 1236 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER) 1237 == PackageManager.PERMISSION_GRANTED) { 1238 return; 1239 } 1240 1241 // Previously we only used the INSTALL_LOCATION_PROVIDER 1242 // check. But that is system or signature 1243 // protection level which is not flexible enough for 1244 // providers installed oustide the system image. So 1245 // also allow providers with a UID matching the 1246 // currently bound package name 1247 1248 int uid = Binder.getCallingUid(); 1249 1250 if (mGeocodeProvider != null) { 1251 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return; 1252 } 1253 for (LocationProviderProxy proxy : mProxyProviders) { 1254 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return; 1255 } 1256 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " + 1257 "or UID of a currently bound location provider"); 1258 } 1259 1260 private boolean doesPackageHaveUid(int uid, String packageName) { 1261 if (packageName == null) { 1262 return false; 1263 } 1264 try { 1265 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0); 1266 if (appInfo.uid != uid) { 1267 return false; 1268 } 1269 } catch (NameNotFoundException e) { 1270 return false; 1271 } 1272 return true; 1273 } 1274 1275 @Override 1276 public void reportLocation(Location location, boolean passive) { 1277 checkCallerIsProvider(); 1278 1279 if (!location.isComplete()) { 1280 Log.w(TAG, "Dropping incomplete location: " + location); 1281 return; 1282 } 1283 1284 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location); 1285 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location); 1286 m.arg1 = (passive ? 1 : 0); 1287 mLocationHandler.sendMessageAtFrontOfQueue(m); 1288 } 1289 1290 1291 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) { 1292 // Always broadcast the first update 1293 if (lastLoc == null) { 1294 return true; 1295 } 1296 1297 // Check whether sufficient time has passed 1298 long minTime = record.mRequest.getFastestInterval(); 1299 long delta = (loc.getElapsedRealtimeNano() - lastLoc.getElapsedRealtimeNano()) / 1000000L; 1300 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) { 1301 return false; 1302 } 1303 1304 // Check whether sufficient distance has been traveled 1305 double minDistance = record.mRequest.getSmallestDisplacement(); 1306 if (minDistance > 0.0) { 1307 if (loc.distanceTo(lastLoc) <= minDistance) { 1308 return false; 1309 } 1310 } 1311 1312 return true; 1313 } 1314 1315 private void handleLocationChangedLocked(Location location, boolean passive) { 1316 if (D) Log.d(TAG, "incoming location: " + location); 1317 1318 long now = SystemClock.elapsedRealtime(); 1319 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider()); 1320 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 1321 if (records == null || records.size() == 0) return; 1322 1323 LocationProviderInterface p = mProvidersByName.get(provider); 1324 if (p == null) return; 1325 1326 // Add the coarse location as an extra 1327 Location coarse = mLocationFudger.getOrCreate(location); 1328 1329 // Update last known locations 1330 Location lastLocation = mLastLocation.get(provider); 1331 if (lastLocation == null) { 1332 lastLocation = new Location(provider); 1333 mLastLocation.put(provider, lastLocation); 1334 } 1335 lastLocation.set(location); 1336 1337 // Fetch latest status update time 1338 long newStatusUpdateTime = p.getStatusUpdateTime(); 1339 1340 // Get latest status 1341 Bundle extras = new Bundle(); 1342 int status = p.getStatus(extras); 1343 1344 ArrayList<Receiver> deadReceivers = null; 1345 ArrayList<UpdateRecord> deadUpdateRecords = null; 1346 1347 // Broadcast location or status to all listeners 1348 for (UpdateRecord r : records) { 1349 Receiver receiver = r.mReceiver; 1350 boolean receiverDead = false; 1351 1352 if (mBlacklist.isBlacklisted(receiver.mPackageName)) { 1353 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " + 1354 receiver.mPackageName); 1355 continue; 1356 } 1357 1358 if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) { 1359 location = lastLocation; // use fine location 1360 } else { 1361 location = coarse; // use coarse location 1362 } 1363 1364 Location lastLoc = r.mLastFixBroadcast; 1365 if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) { 1366 if (lastLoc == null) { 1367 lastLoc = new Location(location); 1368 r.mLastFixBroadcast = lastLoc; 1369 } else { 1370 lastLoc.set(location); 1371 } 1372 if (!receiver.callLocationChangedLocked(location)) { 1373 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver); 1374 receiverDead = true; 1375 } 1376 } 1377 1378 long prevStatusUpdateTime = r.mLastStatusBroadcast; 1379 if ((newStatusUpdateTime > prevStatusUpdateTime) && 1380 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) { 1381 1382 r.mLastStatusBroadcast = newStatusUpdateTime; 1383 if (!receiver.callStatusChangedLocked(provider, status, extras)) { 1384 receiverDead = true; 1385 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver); 1386 } 1387 } 1388 1389 // track expired records 1390 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) { 1391 if (deadUpdateRecords == null) { 1392 deadUpdateRecords = new ArrayList<UpdateRecord>(); 1393 } 1394 deadUpdateRecords.add(r); 1395 } 1396 // track dead receivers 1397 if (receiverDead) { 1398 if (deadReceivers == null) { 1399 deadReceivers = new ArrayList<Receiver>(); 1400 } 1401 if (!deadReceivers.contains(receiver)) { 1402 deadReceivers.add(receiver); 1403 } 1404 } 1405 } 1406 1407 // remove dead records and receivers outside the loop 1408 if (deadReceivers != null) { 1409 for (Receiver receiver : deadReceivers) { 1410 removeUpdatesLocked(receiver); 1411 } 1412 } 1413 if (deadUpdateRecords != null) { 1414 for (UpdateRecord r : deadUpdateRecords) { 1415 r.disposeLocked(true); 1416 } 1417 } 1418 } 1419 1420 private class LocationWorkerHandler extends Handler { 1421 @Override 1422 public void handleMessage(Message msg) { 1423 switch (msg.what) { 1424 case MSG_LOCATION_CHANGED: 1425 handleLocationChanged((Location) msg.obj, msg.arg1 == 1); 1426 break; 1427 } 1428 } 1429 } 1430 1431 private void handleLocationChanged(Location location, boolean passive) { 1432 String provider = location.getProvider(); 1433 1434 if (!passive) { 1435 // notify passive provider of the new location 1436 mPassiveProvider.updateLocation(location); 1437 } 1438 1439 synchronized (mLock) { 1440 if (isAllowedBySettingsLocked(provider)) { 1441 handleLocationChangedLocked(location, passive); 1442 } 1443 } 1444 } 1445 1446 private final PackageMonitor mPackageMonitor = new PackageMonitor() { 1447 @Override 1448 public void onPackageDisappeared(String packageName, int reason) { 1449 // remove all receivers associated with this package name 1450 synchronized (mLock) { 1451 ArrayList<Receiver> deadReceivers = null; 1452 1453 for (Receiver receiver : mReceivers.values()) { 1454 if (receiver.mPackageName.equals(packageName)) { 1455 if (deadReceivers == null) { 1456 deadReceivers = new ArrayList<Receiver>(); 1457 } 1458 deadReceivers.add(receiver); 1459 } 1460 } 1461 1462 // perform removal outside of mReceivers loop 1463 if (deadReceivers != null) { 1464 for (Receiver receiver : deadReceivers) { 1465 removeUpdatesLocked(receiver); 1466 } 1467 } 1468 } 1469 } 1470 }; 1471 1472 // Wake locks 1473 1474 private void incrementPendingBroadcasts() { 1475 synchronized (mWakeLock) { 1476 if (mPendingBroadcasts++ == 0) { 1477 try { 1478 mWakeLock.acquire(); 1479 log("Acquired wakelock"); 1480 } catch (Exception e) { 1481 // This is to catch a runtime exception thrown when we try to release an 1482 // already released lock. 1483 Slog.e(TAG, "exception in acquireWakeLock()", e); 1484 } 1485 } 1486 } 1487 } 1488 1489 private void decrementPendingBroadcasts() { 1490 synchronized (mWakeLock) { 1491 if (--mPendingBroadcasts == 0) { 1492 try { 1493 // Release wake lock 1494 if (mWakeLock.isHeld()) { 1495 mWakeLock.release(); 1496 log("Released wakelock"); 1497 } else { 1498 log("Can't release wakelock again!"); 1499 } 1500 } catch (Exception e) { 1501 // This is to catch a runtime exception thrown when we try to release an 1502 // already released lock. 1503 Slog.e(TAG, "exception in releaseWakeLock()", e); 1504 } 1505 } 1506 } 1507 } 1508 1509 // Geocoder 1510 1511 @Override 1512 public boolean geocoderIsPresent() { 1513 return mGeocodeProvider != null; 1514 } 1515 1516 @Override 1517 public String getFromLocation(double latitude, double longitude, int maxResults, 1518 GeocoderParams params, List<Address> addrs) { 1519 if (mGeocodeProvider != null) { 1520 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, 1521 params, addrs); 1522 } 1523 return null; 1524 } 1525 1526 1527 @Override 1528 public String getFromLocationName(String locationName, 1529 double lowerLeftLatitude, double lowerLeftLongitude, 1530 double upperRightLatitude, double upperRightLongitude, int maxResults, 1531 GeocoderParams params, List<Address> addrs) { 1532 1533 if (mGeocodeProvider != null) { 1534 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude, 1535 lowerLeftLongitude, upperRightLatitude, upperRightLongitude, 1536 maxResults, params, addrs); 1537 } 1538 return null; 1539 } 1540 1541 // Mock Providers 1542 1543 private void checkMockPermissionsSafe() { 1544 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(), 1545 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1; 1546 if (!allowMocks) { 1547 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting"); 1548 } 1549 1550 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) != 1551 PackageManager.PERMISSION_GRANTED) { 1552 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission"); 1553 } 1554 } 1555 1556 @Override 1557 public void addTestProvider(String name, ProviderProperties properties) { 1558 checkMockPermissionsSafe(); 1559 1560 if (LocationManager.PASSIVE_PROVIDER.equals(name)) { 1561 throw new IllegalArgumentException("Cannot mock the passive location provider"); 1562 } 1563 1564 long identity = Binder.clearCallingIdentity(); 1565 synchronized (mLock) { 1566 MockProvider provider = new MockProvider(name, this, properties); 1567 // remove the real provider if we are replacing GPS or network provider 1568 if (LocationManager.GPS_PROVIDER.equals(name) 1569 || LocationManager.NETWORK_PROVIDER.equals(name) 1570 || LocationManager.FUSED_PROVIDER.equals(name)) { 1571 LocationProviderInterface p = mProvidersByName.get(name); 1572 if (p != null) { 1573 removeProviderLocked(p); 1574 } 1575 } 1576 if (mProvidersByName.get(name) != null) { 1577 throw new IllegalArgumentException("Provider \"" + name + "\" already exists"); 1578 } 1579 addProviderLocked(provider); 1580 mMockProviders.put(name, provider); 1581 mLastLocation.put(name, null); 1582 updateProvidersLocked(); 1583 } 1584 Binder.restoreCallingIdentity(identity); 1585 } 1586 1587 @Override 1588 public void removeTestProvider(String provider) { 1589 checkMockPermissionsSafe(); 1590 synchronized (mLock) { 1591 MockProvider mockProvider = mMockProviders.get(provider); 1592 if (mockProvider == null) { 1593 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1594 } 1595 long identity = Binder.clearCallingIdentity(); 1596 removeProviderLocked(mProvidersByName.get(provider)); 1597 mMockProviders.remove(mockProvider); 1598 1599 // reinstate real provider if available 1600 LocationProviderInterface realProvider = mRealProviders.get(provider); 1601 if (realProvider != null) { 1602 addProviderLocked(realProvider); 1603 } 1604 mLastLocation.put(provider, null); 1605 updateProvidersLocked(); 1606 Binder.restoreCallingIdentity(identity); 1607 } 1608 } 1609 1610 @Override 1611 public void setTestProviderLocation(String provider, Location loc) { 1612 checkMockPermissionsSafe(); 1613 synchronized (mLock) { 1614 MockProvider mockProvider = mMockProviders.get(provider); 1615 if (mockProvider == null) { 1616 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1617 } 1618 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required 1619 long identity = Binder.clearCallingIdentity(); 1620 mockProvider.setLocation(loc); 1621 Binder.restoreCallingIdentity(identity); 1622 } 1623 } 1624 1625 @Override 1626 public void clearTestProviderLocation(String provider) { 1627 checkMockPermissionsSafe(); 1628 synchronized (mLock) { 1629 MockProvider mockProvider = mMockProviders.get(provider); 1630 if (mockProvider == null) { 1631 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1632 } 1633 mockProvider.clearLocation(); 1634 } 1635 } 1636 1637 @Override 1638 public void setTestProviderEnabled(String provider, boolean enabled) { 1639 checkMockPermissionsSafe(); 1640 synchronized (mLock) { 1641 MockProvider mockProvider = mMockProviders.get(provider); 1642 if (mockProvider == null) { 1643 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1644 } 1645 long identity = Binder.clearCallingIdentity(); 1646 if (enabled) { 1647 mockProvider.enable(); 1648 mEnabledProviders.add(provider); 1649 mDisabledProviders.remove(provider); 1650 } else { 1651 mockProvider.disable(); 1652 mEnabledProviders.remove(provider); 1653 mDisabledProviders.add(provider); 1654 } 1655 updateProvidersLocked(); 1656 Binder.restoreCallingIdentity(identity); 1657 } 1658 } 1659 1660 @Override 1661 public void clearTestProviderEnabled(String provider) { 1662 checkMockPermissionsSafe(); 1663 synchronized (mLock) { 1664 MockProvider mockProvider = mMockProviders.get(provider); 1665 if (mockProvider == null) { 1666 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1667 } 1668 long identity = Binder.clearCallingIdentity(); 1669 mEnabledProviders.remove(provider); 1670 mDisabledProviders.remove(provider); 1671 updateProvidersLocked(); 1672 Binder.restoreCallingIdentity(identity); 1673 } 1674 } 1675 1676 @Override 1677 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) { 1678 checkMockPermissionsSafe(); 1679 synchronized (mLock) { 1680 MockProvider mockProvider = mMockProviders.get(provider); 1681 if (mockProvider == null) { 1682 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1683 } 1684 mockProvider.setStatus(status, extras, updateTime); 1685 } 1686 } 1687 1688 @Override 1689 public void clearTestProviderStatus(String provider) { 1690 checkMockPermissionsSafe(); 1691 synchronized (mLock) { 1692 MockProvider mockProvider = mMockProviders.get(provider); 1693 if (mockProvider == null) { 1694 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1695 } 1696 mockProvider.clearStatus(); 1697 } 1698 } 1699 1700 private void log(String log) { 1701 if (Log.isLoggable(TAG, Log.VERBOSE)) { 1702 Slog.d(TAG, log); 1703 } 1704 } 1705 1706 @Override 1707 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1708 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 1709 != PackageManager.PERMISSION_GRANTED) { 1710 pw.println("Permission Denial: can't dump LocationManagerService from from pid=" 1711 + Binder.getCallingPid() 1712 + ", uid=" + Binder.getCallingUid()); 1713 return; 1714 } 1715 1716 synchronized (mLock) { 1717 pw.println("Current Location Manager state:"); 1718 pw.println(" Location Listeners:"); 1719 for (Receiver receiver : mReceivers.values()) { 1720 pw.println(" " + receiver); 1721 } 1722 pw.println(" Records by Provider:"); 1723 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) { 1724 pw.println(" " + entry.getKey() + ":"); 1725 for (UpdateRecord record : entry.getValue()) { 1726 pw.println(" " + record); 1727 } 1728 } 1729 pw.println(" Last Known Locations:"); 1730 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) { 1731 String provider = entry.getKey(); 1732 Location location = entry.getValue(); 1733 pw.println(" " + provider + ": " + location); 1734 } 1735 1736 mGeofenceManager.dump(pw); 1737 1738 if (mEnabledProviders.size() > 0) { 1739 pw.println(" Enabled Providers:"); 1740 for (String i : mEnabledProviders) { 1741 pw.println(" " + i); 1742 } 1743 1744 } 1745 if (mDisabledProviders.size() > 0) { 1746 pw.println(" Disabled Providers:"); 1747 for (String i : mDisabledProviders) { 1748 pw.println(" " + i); 1749 } 1750 } 1751 pw.append(" "); 1752 mBlacklist.dump(pw); 1753 if (mMockProviders.size() > 0) { 1754 pw.println(" Mock Providers:"); 1755 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) { 1756 i.getValue().dump(pw, " "); 1757 } 1758 } 1759 1760 pw.append(" fudger: "); 1761 mLocationFudger.dump(fd, pw, args); 1762 1763 if (args.length > 0 && "short".equals(args[0])) { 1764 return; 1765 } 1766 for (LocationProviderInterface provider: mProviders) { 1767 pw.print(provider.getName() + " Internal State"); 1768 if (provider instanceof LocationProviderProxy) { 1769 LocationProviderProxy proxy = (LocationProviderProxy) provider; 1770 pw.print(" (" + proxy.getConnectedPackageName() + ")"); 1771 } 1772 pw.println(":"); 1773 provider.dump(fd, pw, args); 1774 } 1775 } 1776 } 1777} 1778