LocationManagerService.java revision 4035f5a7c191a68bc9a5912ce44c43c82e9e5dbf
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 // so wakelock calls will succeed (not totally sure this is still needed) 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 // so wakelock calls will succeed (not totally sure this is still needed) 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 mGeofenceManager.addFence(request, geofence, intent, Binder.getCallingUid(), packageName); 1111 } 1112 1113 @Override 1114 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) { 1115 checkPermission(); 1116 checkPendingIntent(intent); 1117 checkPackageName(packageName); 1118 1119 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent); 1120 1121 mGeofenceManager.removeFence(geofence, intent); 1122 } 1123 1124 1125 @Override 1126 public boolean addGpsStatusListener(IGpsStatusListener listener) { 1127 if (mGpsStatusProvider == null) { 1128 return false; 1129 } 1130 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) != 1131 PackageManager.PERMISSION_GRANTED) { 1132 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); 1133 } 1134 1135 try { 1136 mGpsStatusProvider.addGpsStatusListener(listener); 1137 } catch (RemoteException e) { 1138 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e); 1139 return false; 1140 } 1141 return true; 1142 } 1143 1144 @Override 1145 public void removeGpsStatusListener(IGpsStatusListener listener) { 1146 synchronized (mLock) { 1147 try { 1148 mGpsStatusProvider.removeGpsStatusListener(listener); 1149 } catch (Exception e) { 1150 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e); 1151 } 1152 } 1153 } 1154 1155 @Override 1156 public boolean sendExtraCommand(String provider, String command, Bundle extras) { 1157 if (provider == null) { 1158 // throw NullPointerException to remain compatible with previous implementation 1159 throw new NullPointerException(); 1160 } 1161 1162 checkPermission(); 1163 // and check for ACCESS_LOCATION_EXTRA_COMMANDS 1164 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS) 1165 != PackageManager.PERMISSION_GRANTED)) { 1166 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission"); 1167 } 1168 1169 synchronized (mLock) { 1170 LocationProviderInterface p = mProvidersByName.get(provider); 1171 if (p == null) return false; 1172 1173 return p.sendExtraCommand(command, extras); 1174 } 1175 } 1176 1177 @Override 1178 public boolean sendNiResponse(int notifId, int userResponse) { 1179 if (Binder.getCallingUid() != Process.myUid()) { 1180 throw new SecurityException( 1181 "calling sendNiResponse from outside of the system is not allowed"); 1182 } 1183 try { 1184 return mNetInitiatedListener.sendNiResponse(notifId, userResponse); 1185 } catch (RemoteException e) { 1186 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse"); 1187 return false; 1188 } 1189 } 1190 1191 /** 1192 * @return null if the provider does not exist 1193 * @throws SecurityException if the provider is not allowed to be 1194 * accessed by the caller 1195 */ 1196 @Override 1197 public ProviderProperties getProviderProperties(String provider) { 1198 checkPermission(); 1199 1200 LocationProviderInterface p; 1201 synchronized (mLock) { 1202 p = mProvidersByName.get(provider); 1203 } 1204 1205 if (p == null) return null; 1206 return p.getProperties(); 1207 } 1208 1209 @Override 1210 public boolean isProviderEnabled(String provider) { 1211 checkPermission(); 1212 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false; 1213 1214 synchronized (mLock) { 1215 LocationProviderInterface p = mProvidersByName.get(provider); 1216 if (p == null) return false; 1217 1218 return isAllowedBySettingsLocked(provider); 1219 } 1220 } 1221 1222 private void checkCallerIsProvider() { 1223 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER) 1224 == PackageManager.PERMISSION_GRANTED) { 1225 return; 1226 } 1227 1228 // Previously we only used the INSTALL_LOCATION_PROVIDER 1229 // check. But that is system or signature 1230 // protection level which is not flexible enough for 1231 // providers installed oustide the system image. So 1232 // also allow providers with a UID matching the 1233 // currently bound package name 1234 1235 int uid = Binder.getCallingUid(); 1236 1237 if (mGeocodeProvider != null) { 1238 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return; 1239 } 1240 for (LocationProviderProxy proxy : mProxyProviders) { 1241 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return; 1242 } 1243 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " + 1244 "or UID of a currently bound location provider"); 1245 } 1246 1247 private boolean doesPackageHaveUid(int uid, String packageName) { 1248 if (packageName == null) { 1249 return false; 1250 } 1251 try { 1252 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0); 1253 if (appInfo.uid != uid) { 1254 return false; 1255 } 1256 } catch (NameNotFoundException e) { 1257 return false; 1258 } 1259 return true; 1260 } 1261 1262 @Override 1263 public void reportLocation(Location location, boolean passive) { 1264 checkCallerIsProvider(); 1265 1266 if (!location.isComplete()) { 1267 Log.w(TAG, "Dropping incomplete location: " + location); 1268 return; 1269 } 1270 1271 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location); 1272 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location); 1273 m.arg1 = (passive ? 1 : 0); 1274 mLocationHandler.sendMessageAtFrontOfQueue(m); 1275 } 1276 1277 1278 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) { 1279 // Always broadcast the first update 1280 if (lastLoc == null) { 1281 return true; 1282 } 1283 1284 // Check whether sufficient time has passed 1285 long minTime = record.mRequest.getFastestInterval(); 1286 long delta = (loc.getElapsedRealtimeNano() - lastLoc.getElapsedRealtimeNano()) / 1000000L; 1287 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) { 1288 return false; 1289 } 1290 1291 // Check whether sufficient distance has been traveled 1292 double minDistance = record.mRequest.getSmallestDisplacement(); 1293 if (minDistance > 0.0) { 1294 if (loc.distanceTo(lastLoc) <= minDistance) { 1295 return false; 1296 } 1297 } 1298 1299 return true; 1300 } 1301 1302 private void handleLocationChangedLocked(Location location, boolean passive) { 1303 if (D) Log.d(TAG, "incoming location: " + location); 1304 1305 long now = SystemClock.elapsedRealtime(); 1306 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider()); 1307 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 1308 if (records == null || records.size() == 0) return; 1309 1310 LocationProviderInterface p = mProvidersByName.get(provider); 1311 if (p == null) return; 1312 1313 // Add the coarse location as an extra 1314 Location coarse = mLocationFudger.getOrCreate(location); 1315 1316 // Update last known locations 1317 Location lastLocation = mLastLocation.get(provider); 1318 if (lastLocation == null) { 1319 lastLocation = new Location(provider); 1320 mLastLocation.put(provider, lastLocation); 1321 } 1322 lastLocation.set(location); 1323 1324 // Fetch latest status update time 1325 long newStatusUpdateTime = p.getStatusUpdateTime(); 1326 1327 // Get latest status 1328 Bundle extras = new Bundle(); 1329 int status = p.getStatus(extras); 1330 1331 ArrayList<Receiver> deadReceivers = null; 1332 ArrayList<UpdateRecord> deadUpdateRecords = null; 1333 1334 // Broadcast location or status to all listeners 1335 for (UpdateRecord r : records) { 1336 Receiver receiver = r.mReceiver; 1337 boolean receiverDead = false; 1338 1339 if (mBlacklist.isBlacklisted(receiver.mPackageName)) { 1340 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " + 1341 receiver.mPackageName); 1342 continue; 1343 } 1344 1345 if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) { 1346 location = lastLocation; // use fine location 1347 } else { 1348 location = coarse; // use coarse location 1349 } 1350 1351 Location lastLoc = r.mLastFixBroadcast; 1352 if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) { 1353 if (lastLoc == null) { 1354 lastLoc = new Location(location); 1355 r.mLastFixBroadcast = lastLoc; 1356 } else { 1357 lastLoc.set(location); 1358 } 1359 if (!receiver.callLocationChangedLocked(location)) { 1360 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver); 1361 receiverDead = true; 1362 } 1363 } 1364 1365 long prevStatusUpdateTime = r.mLastStatusBroadcast; 1366 if ((newStatusUpdateTime > prevStatusUpdateTime) && 1367 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) { 1368 1369 r.mLastStatusBroadcast = newStatusUpdateTime; 1370 if (!receiver.callStatusChangedLocked(provider, status, extras)) { 1371 receiverDead = true; 1372 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver); 1373 } 1374 } 1375 1376 // track expired records 1377 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) { 1378 if (deadUpdateRecords == null) { 1379 deadUpdateRecords = new ArrayList<UpdateRecord>(); 1380 } 1381 deadUpdateRecords.add(r); 1382 } 1383 // track dead receivers 1384 if (receiverDead) { 1385 if (deadReceivers == null) { 1386 deadReceivers = new ArrayList<Receiver>(); 1387 } 1388 if (!deadReceivers.contains(receiver)) { 1389 deadReceivers.add(receiver); 1390 } 1391 } 1392 } 1393 1394 // remove dead records and receivers outside the loop 1395 if (deadReceivers != null) { 1396 for (Receiver receiver : deadReceivers) { 1397 removeUpdatesLocked(receiver); 1398 } 1399 } 1400 if (deadUpdateRecords != null) { 1401 for (UpdateRecord r : deadUpdateRecords) { 1402 r.disposeLocked(true); 1403 } 1404 } 1405 } 1406 1407 private class LocationWorkerHandler extends Handler { 1408 @Override 1409 public void handleMessage(Message msg) { 1410 switch (msg.what) { 1411 case MSG_LOCATION_CHANGED: 1412 handleLocationChanged((Location) msg.obj, msg.arg1 == 1); 1413 break; 1414 } 1415 } 1416 } 1417 1418 private void handleLocationChanged(Location location, boolean passive) { 1419 String provider = location.getProvider(); 1420 1421 if (!passive) { 1422 // notify passive provider of the new location 1423 mPassiveProvider.updateLocation(location); 1424 } 1425 1426 synchronized (mLock) { 1427 if (isAllowedBySettingsLocked(provider)) { 1428 handleLocationChangedLocked(location, passive); 1429 } 1430 } 1431 } 1432 1433 private final PackageMonitor mPackageMonitor = new PackageMonitor() { 1434 @Override 1435 public void onPackageDisappeared(String packageName, int reason) { 1436 // remove all receivers associated with this package name 1437 synchronized (mLock) { 1438 ArrayList<Receiver> deadReceivers = null; 1439 1440 for (Receiver receiver : mReceivers.values()) { 1441 if (receiver.mPackageName.equals(packageName)) { 1442 if (deadReceivers == null) { 1443 deadReceivers = new ArrayList<Receiver>(); 1444 } 1445 deadReceivers.add(receiver); 1446 } 1447 } 1448 1449 // perform removal outside of mReceivers loop 1450 if (deadReceivers != null) { 1451 for (Receiver receiver : deadReceivers) { 1452 removeUpdatesLocked(receiver); 1453 } 1454 } 1455 } 1456 } 1457 }; 1458 1459 // Wake locks 1460 1461 private void incrementPendingBroadcasts() { 1462 synchronized (mWakeLock) { 1463 if (mPendingBroadcasts++ == 0) { 1464 try { 1465 mWakeLock.acquire(); 1466 log("Acquired wakelock"); 1467 } catch (Exception e) { 1468 // This is to catch a runtime exception thrown when we try to release an 1469 // already released lock. 1470 Slog.e(TAG, "exception in acquireWakeLock()", e); 1471 } 1472 } 1473 } 1474 } 1475 1476 private void decrementPendingBroadcasts() { 1477 synchronized (mWakeLock) { 1478 if (--mPendingBroadcasts == 0) { 1479 try { 1480 // Release wake lock 1481 if (mWakeLock.isHeld()) { 1482 mWakeLock.release(); 1483 log("Released wakelock"); 1484 } else { 1485 log("Can't release wakelock again!"); 1486 } 1487 } catch (Exception e) { 1488 // This is to catch a runtime exception thrown when we try to release an 1489 // already released lock. 1490 Slog.e(TAG, "exception in releaseWakeLock()", e); 1491 } 1492 } 1493 } 1494 } 1495 1496 // Geocoder 1497 1498 @Override 1499 public boolean geocoderIsPresent() { 1500 return mGeocodeProvider != null; 1501 } 1502 1503 @Override 1504 public String getFromLocation(double latitude, double longitude, int maxResults, 1505 GeocoderParams params, List<Address> addrs) { 1506 if (mGeocodeProvider != null) { 1507 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, 1508 params, addrs); 1509 } 1510 return null; 1511 } 1512 1513 1514 @Override 1515 public String getFromLocationName(String locationName, 1516 double lowerLeftLatitude, double lowerLeftLongitude, 1517 double upperRightLatitude, double upperRightLongitude, int maxResults, 1518 GeocoderParams params, List<Address> addrs) { 1519 1520 if (mGeocodeProvider != null) { 1521 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude, 1522 lowerLeftLongitude, upperRightLatitude, upperRightLongitude, 1523 maxResults, params, addrs); 1524 } 1525 return null; 1526 } 1527 1528 // Mock Providers 1529 1530 private void checkMockPermissionsSafe() { 1531 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(), 1532 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1; 1533 if (!allowMocks) { 1534 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting"); 1535 } 1536 1537 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) != 1538 PackageManager.PERMISSION_GRANTED) { 1539 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission"); 1540 } 1541 } 1542 1543 @Override 1544 public void addTestProvider(String name, ProviderProperties properties) { 1545 checkMockPermissionsSafe(); 1546 1547 if (LocationManager.PASSIVE_PROVIDER.equals(name)) { 1548 throw new IllegalArgumentException("Cannot mock the passive location provider"); 1549 } 1550 1551 long identity = Binder.clearCallingIdentity(); 1552 synchronized (mLock) { 1553 MockProvider provider = new MockProvider(name, this, properties); 1554 // remove the real provider if we are replacing GPS or network provider 1555 if (LocationManager.GPS_PROVIDER.equals(name) 1556 || LocationManager.NETWORK_PROVIDER.equals(name)) { 1557 LocationProviderInterface p = mProvidersByName.get(name); 1558 if (p != null) { 1559 removeProviderLocked(p); 1560 } 1561 } 1562 if (mProvidersByName.get(name) != null) { 1563 throw new IllegalArgumentException("Provider \"" + name + "\" already exists"); 1564 } 1565 addProviderLocked(provider); 1566 mMockProviders.put(name, provider); 1567 mLastLocation.put(name, null); 1568 updateProvidersLocked(); 1569 } 1570 Binder.restoreCallingIdentity(identity); 1571 } 1572 1573 @Override 1574 public void removeTestProvider(String provider) { 1575 checkMockPermissionsSafe(); 1576 synchronized (mLock) { 1577 MockProvider mockProvider = mMockProviders.get(provider); 1578 if (mockProvider == null) { 1579 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1580 } 1581 long identity = Binder.clearCallingIdentity(); 1582 removeProviderLocked(mProvidersByName.get(provider)); 1583 mMockProviders.remove(mockProvider); 1584 1585 // reinstate real provider if available 1586 LocationProviderInterface realProvider = mRealProviders.get(provider); 1587 if (realProvider != null) { 1588 addProviderLocked(realProvider); 1589 } 1590 mLastLocation.put(provider, null); 1591 updateProvidersLocked(); 1592 Binder.restoreCallingIdentity(identity); 1593 } 1594 } 1595 1596 @Override 1597 public void setTestProviderLocation(String provider, Location loc) { 1598 checkMockPermissionsSafe(); 1599 synchronized (mLock) { 1600 MockProvider mockProvider = mMockProviders.get(provider); 1601 if (mockProvider == null) { 1602 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1603 } 1604 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required 1605 long identity = Binder.clearCallingIdentity(); 1606 mockProvider.setLocation(loc); 1607 Binder.restoreCallingIdentity(identity); 1608 } 1609 } 1610 1611 @Override 1612 public void clearTestProviderLocation(String provider) { 1613 checkMockPermissionsSafe(); 1614 synchronized (mLock) { 1615 MockProvider mockProvider = mMockProviders.get(provider); 1616 if (mockProvider == null) { 1617 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1618 } 1619 mockProvider.clearLocation(); 1620 } 1621 } 1622 1623 @Override 1624 public void setTestProviderEnabled(String provider, boolean enabled) { 1625 checkMockPermissionsSafe(); 1626 synchronized (mLock) { 1627 MockProvider mockProvider = mMockProviders.get(provider); 1628 if (mockProvider == null) { 1629 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1630 } 1631 long identity = Binder.clearCallingIdentity(); 1632 if (enabled) { 1633 mockProvider.enable(); 1634 mEnabledProviders.add(provider); 1635 mDisabledProviders.remove(provider); 1636 } else { 1637 mockProvider.disable(); 1638 mEnabledProviders.remove(provider); 1639 mDisabledProviders.add(provider); 1640 } 1641 updateProvidersLocked(); 1642 Binder.restoreCallingIdentity(identity); 1643 } 1644 } 1645 1646 @Override 1647 public void clearTestProviderEnabled(String provider) { 1648 checkMockPermissionsSafe(); 1649 synchronized (mLock) { 1650 MockProvider mockProvider = mMockProviders.get(provider); 1651 if (mockProvider == null) { 1652 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1653 } 1654 long identity = Binder.clearCallingIdentity(); 1655 mEnabledProviders.remove(provider); 1656 mDisabledProviders.remove(provider); 1657 updateProvidersLocked(); 1658 Binder.restoreCallingIdentity(identity); 1659 } 1660 } 1661 1662 @Override 1663 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) { 1664 checkMockPermissionsSafe(); 1665 synchronized (mLock) { 1666 MockProvider mockProvider = mMockProviders.get(provider); 1667 if (mockProvider == null) { 1668 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1669 } 1670 mockProvider.setStatus(status, extras, updateTime); 1671 } 1672 } 1673 1674 @Override 1675 public void clearTestProviderStatus(String provider) { 1676 checkMockPermissionsSafe(); 1677 synchronized (mLock) { 1678 MockProvider mockProvider = mMockProviders.get(provider); 1679 if (mockProvider == null) { 1680 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1681 } 1682 mockProvider.clearStatus(); 1683 } 1684 } 1685 1686 private void log(String log) { 1687 if (Log.isLoggable(TAG, Log.VERBOSE)) { 1688 Slog.d(TAG, log); 1689 } 1690 } 1691 1692 @Override 1693 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1694 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 1695 != PackageManager.PERMISSION_GRANTED) { 1696 pw.println("Permission Denial: can't dump LocationManagerService from from pid=" 1697 + Binder.getCallingPid() 1698 + ", uid=" + Binder.getCallingUid()); 1699 return; 1700 } 1701 1702 synchronized (mLock) { 1703 pw.println("Current Location Manager state:"); 1704 pw.println(" Location Listeners:"); 1705 for (Receiver receiver : mReceivers.values()) { 1706 pw.println(" " + receiver); 1707 } 1708 pw.println(" Records by Provider:"); 1709 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) { 1710 pw.println(" " + entry.getKey() + ":"); 1711 for (UpdateRecord record : entry.getValue()) { 1712 pw.println(" " + record); 1713 } 1714 } 1715 pw.println(" Last Known Locations:"); 1716 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) { 1717 String provider = entry.getKey(); 1718 Location location = entry.getValue(); 1719 pw.println(" " + provider + ": " + location); 1720 } 1721 1722 mGeofenceManager.dump(pw); 1723 1724 if (mEnabledProviders.size() > 0) { 1725 pw.println(" Enabled Providers:"); 1726 for (String i : mEnabledProviders) { 1727 pw.println(" " + i); 1728 } 1729 1730 } 1731 if (mDisabledProviders.size() > 0) { 1732 pw.println(" Disabled Providers:"); 1733 for (String i : mDisabledProviders) { 1734 pw.println(" " + i); 1735 } 1736 } 1737 pw.append(" "); 1738 mBlacklist.dump(pw); 1739 if (mMockProviders.size() > 0) { 1740 pw.println(" Mock Providers:"); 1741 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) { 1742 i.getValue().dump(pw, " "); 1743 } 1744 } 1745 1746 pw.append(" fudger: "); 1747 mLocationFudger.dump(fd, pw, args); 1748 1749 if (args.length > 0 && "short".equals(args[0])) { 1750 return; 1751 } 1752 for (LocationProviderInterface provider: mProviders) { 1753 pw.print(provider.getName() + " Internal State"); 1754 if (provider instanceof LocationProviderProxy) { 1755 LocationProviderProxy proxy = (LocationProviderProxy) provider; 1756 pw.print(" (" + proxy.getConnectedPackageName() + ")"); 1757 } 1758 pw.println(":"); 1759 provider.dump(fd, pw, args); 1760 } 1761 } 1762 } 1763} 1764