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