LocationManagerService.java revision 7e9f4eb2608148436cef36c9969bf8a599b39e72
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.Activity; 20import android.app.PendingIntent; 21import android.content.BroadcastReceiver; 22import android.content.ComponentName; 23import android.content.ContentQueryMap; 24import android.content.ContentResolver; 25import android.content.Context; 26import android.content.Intent; 27import android.content.IntentFilter; 28import android.content.ServiceConnection; 29import android.content.pm.PackageManager; 30import android.content.res.Resources; 31import android.database.Cursor; 32import android.location.Address; 33import android.location.Criteria; 34import android.location.GeocoderParams; 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.net.ConnectivityManager; 44import android.net.NetworkInfo; 45import android.net.Uri; 46import android.os.Binder; 47import android.os.Bundle; 48import android.os.Handler; 49import android.os.IBinder; 50import android.os.Looper; 51import android.os.Message; 52import android.os.PowerManager; 53import android.os.Process; 54import android.os.RemoteException; 55import android.os.WorkSource; 56import android.provider.Settings; 57import android.util.Log; 58import android.util.Slog; 59import android.util.PrintWriterPrinter; 60 61import com.android.internal.location.GpsNetInitiatedHandler; 62 63import com.android.server.location.GeocoderProxy; 64import com.android.server.location.GpsLocationProvider; 65import com.android.server.location.LocationProviderInterface; 66import com.android.server.location.LocationProviderProxy; 67import com.android.server.location.MockProvider; 68import com.android.server.location.PassiveProvider; 69 70import java.io.FileDescriptor; 71import java.io.PrintWriter; 72import java.util.ArrayList; 73import java.util.Collections; 74import java.util.Comparator; 75import java.util.HashMap; 76import java.util.HashSet; 77import java.util.List; 78import java.util.Map; 79import java.util.Observable; 80import java.util.Observer; 81import java.util.Set; 82 83/** 84 * The service class that manages LocationProviders and issues location 85 * updates and alerts. 86 * 87 * {@hide} 88 */ 89public class LocationManagerService extends ILocationManager.Stub implements Runnable { 90 private static final String TAG = "LocationManagerService"; 91 private static final boolean LOCAL_LOGV = false; 92 93 // The last time a location was written, by provider name. 94 private HashMap<String,Long> mLastWriteTime = new HashMap<String,Long>(); 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 // Set of providers that are explicitly enabled 108 private final Set<String> mEnabledProviders = new HashSet<String>(); 109 110 // Set of providers that are explicitly disabled 111 private final Set<String> mDisabledProviders = new HashSet<String>(); 112 113 // Locations, status values, and extras for mock providers 114 private final HashMap<String,MockProvider> mMockProviders = new HashMap<String,MockProvider>(); 115 116 private static boolean sProvidersLoaded = false; 117 118 private final Context mContext; 119 private GeocoderProxy mGeocodeProvider; 120 private IGpsStatusProvider mGpsStatusProvider; 121 private INetInitiatedListener mNetInitiatedListener; 122 private LocationWorkerHandler mLocationHandler; 123 124 // Cache the real providers for use in addTestProvider() and removeTestProvider() 125 LocationProviderInterface mNetworkLocationProvider; 126 LocationProviderInterface mGpsLocationProvider; 127 128 // Handler messages 129 private static final int MESSAGE_LOCATION_CHANGED = 1; 130 131 // wakelock variables 132 private final static String WAKELOCK_KEY = "LocationManagerService"; 133 private PowerManager.WakeLock mWakeLock = null; 134 private int mPendingBroadcasts; 135 136 /** 137 * List of all receivers. 138 */ 139 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>(); 140 141 142 /** 143 * List of location providers. 144 */ 145 private final ArrayList<LocationProviderInterface> mProviders = 146 new ArrayList<LocationProviderInterface>(); 147 private final HashMap<String, LocationProviderInterface> mProvidersByName 148 = new HashMap<String, LocationProviderInterface>(); 149 150 /** 151 * Object used internally for synchronization 152 */ 153 private final Object mLock = new Object(); 154 155 /** 156 * Mapping from provider name to all its UpdateRecords 157 */ 158 private final HashMap<String,ArrayList<UpdateRecord>> mRecordsByProvider = 159 new HashMap<String,ArrayList<UpdateRecord>>(); 160 161 /** 162 * Temporary filled in when computing min time for a provider. Access is 163 * protected by global lock mLock. 164 */ 165 private final WorkSource mTmpWorkSource = new WorkSource(); 166 167 // Proximity listeners 168 private Receiver mProximityReceiver = null; 169 private ILocationListener mProximityListener = null; 170 private HashMap<PendingIntent,ProximityAlert> mProximityAlerts = 171 new HashMap<PendingIntent,ProximityAlert>(); 172 private HashSet<ProximityAlert> mProximitiesEntered = 173 new HashSet<ProximityAlert>(); 174 175 // Last known location for each provider 176 private HashMap<String,Location> mLastKnownLocation = 177 new HashMap<String,Location>(); 178 179 private int mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE; 180 181 // for Settings change notification 182 private ContentQueryMap mSettings; 183 184 /** 185 * A wrapper class holding either an ILocationListener or a PendingIntent to receive 186 * location updates. 187 */ 188 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished { 189 final ILocationListener mListener; 190 final PendingIntent mPendingIntent; 191 final Object mKey; 192 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>(); 193 int mPendingBroadcasts; 194 195 Receiver(ILocationListener listener) { 196 mListener = listener; 197 mPendingIntent = null; 198 mKey = listener.asBinder(); 199 } 200 201 Receiver(PendingIntent intent) { 202 mPendingIntent = intent; 203 mListener = null; 204 mKey = intent; 205 } 206 207 @Override 208 public boolean equals(Object otherObj) { 209 if (otherObj instanceof Receiver) { 210 return mKey.equals( 211 ((Receiver)otherObj).mKey); 212 } 213 return false; 214 } 215 216 @Override 217 public int hashCode() { 218 return mKey.hashCode(); 219 } 220 221 @Override 222 public String toString() { 223 if (mListener != null) { 224 return "Receiver{" 225 + Integer.toHexString(System.identityHashCode(this)) 226 + " Listener " + mKey + "}"; 227 } else { 228 return "Receiver{" 229 + Integer.toHexString(System.identityHashCode(this)) 230 + " Intent " + mKey + "}"; 231 } 232 } 233 234 public boolean isListener() { 235 return mListener != null; 236 } 237 238 public boolean isPendingIntent() { 239 return mPendingIntent != null; 240 } 241 242 public ILocationListener getListener() { 243 if (mListener != null) { 244 return mListener; 245 } 246 throw new IllegalStateException("Request for non-existent listener"); 247 } 248 249 public PendingIntent getPendingIntent() { 250 if (mPendingIntent != null) { 251 return mPendingIntent; 252 } 253 throw new IllegalStateException("Request for non-existent intent"); 254 } 255 256 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) { 257 if (mListener != null) { 258 try { 259 synchronized (this) { 260 // synchronize to ensure incrementPendingBroadcastsLocked() 261 // is called before decrementPendingBroadcasts() 262 mListener.onStatusChanged(provider, status, extras); 263 if (mListener != mProximityListener) { 264 // call this after broadcasting so we do not increment 265 // if we throw an exeption. 266 incrementPendingBroadcastsLocked(); 267 } 268 } 269 } catch (RemoteException e) { 270 return false; 271 } 272 } else { 273 Intent statusChanged = new Intent(); 274 statusChanged.putExtras(extras); 275 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status); 276 try { 277 synchronized (this) { 278 // synchronize to ensure incrementPendingBroadcastsLocked() 279 // is called before decrementPendingBroadcasts() 280 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler); 281 // call this after broadcasting so we do not increment 282 // if we throw an exeption. 283 incrementPendingBroadcastsLocked(); 284 } 285 } catch (PendingIntent.CanceledException e) { 286 return false; 287 } 288 } 289 return true; 290 } 291 292 public boolean callLocationChangedLocked(Location location) { 293 if (mListener != null) { 294 try { 295 synchronized (this) { 296 // synchronize to ensure incrementPendingBroadcastsLocked() 297 // is called before decrementPendingBroadcasts() 298 mListener.onLocationChanged(location); 299 if (mListener != mProximityListener) { 300 // call this after broadcasting so we do not increment 301 // if we throw an exeption. 302 incrementPendingBroadcastsLocked(); 303 } 304 } 305 } catch (RemoteException e) { 306 return false; 307 } 308 } else { 309 Intent locationChanged = new Intent(); 310 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location); 311 try { 312 synchronized (this) { 313 // synchronize to ensure incrementPendingBroadcastsLocked() 314 // is called before decrementPendingBroadcasts() 315 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler); 316 // call this after broadcasting so we do not increment 317 // if we throw an exeption. 318 incrementPendingBroadcastsLocked(); 319 } 320 } catch (PendingIntent.CanceledException e) { 321 return false; 322 } 323 } 324 return true; 325 } 326 327 public boolean callProviderEnabledLocked(String provider, boolean enabled) { 328 if (mListener != null) { 329 try { 330 synchronized (this) { 331 // synchronize to ensure incrementPendingBroadcastsLocked() 332 // is called before decrementPendingBroadcasts() 333 if (enabled) { 334 mListener.onProviderEnabled(provider); 335 } else { 336 mListener.onProviderDisabled(provider); 337 } 338 if (mListener != mProximityListener) { 339 // call this after broadcasting so we do not increment 340 // if we throw an exeption. 341 incrementPendingBroadcastsLocked(); 342 } 343 } 344 } catch (RemoteException e) { 345 return false; 346 } 347 } else { 348 Intent providerIntent = new Intent(); 349 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled); 350 try { 351 synchronized (this) { 352 // synchronize to ensure incrementPendingBroadcastsLocked() 353 // is called before decrementPendingBroadcasts() 354 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler); 355 // call this after broadcasting so we do not increment 356 // if we throw an exeption. 357 incrementPendingBroadcastsLocked(); 358 } 359 } catch (PendingIntent.CanceledException e) { 360 return false; 361 } 362 } 363 return true; 364 } 365 366 public void binderDied() { 367 if (LOCAL_LOGV) { 368 Slog.v(TAG, "Location listener died"); 369 } 370 synchronized (mLock) { 371 removeUpdatesLocked(this); 372 } 373 synchronized (this) { 374 if (mPendingBroadcasts > 0) { 375 LocationManagerService.this.decrementPendingBroadcasts(); 376 mPendingBroadcasts = 0; 377 } 378 } 379 } 380 381 public void onSendFinished(PendingIntent pendingIntent, Intent intent, 382 int resultCode, String resultData, Bundle resultExtras) { 383 synchronized (this) { 384 decrementPendingBroadcastsLocked(); 385 } 386 } 387 388 // this must be called while synchronized by caller in a synchronized block 389 // containing the sending of the broadcaset 390 private void incrementPendingBroadcastsLocked() { 391 if (mPendingBroadcasts++ == 0) { 392 LocationManagerService.this.incrementPendingBroadcasts(); 393 } 394 } 395 396 private void decrementPendingBroadcastsLocked() { 397 if (--mPendingBroadcasts == 0) { 398 LocationManagerService.this.decrementPendingBroadcasts(); 399 } 400 } 401 } 402 403 public void locationCallbackFinished(ILocationListener listener) { 404 //Do not use getReceiver here as that will add the ILocationListener to 405 //the receiver list if it is not found. If it is not found then the 406 //LocationListener was removed when it had a pending broadcast and should 407 //not be added back. 408 IBinder binder = listener.asBinder(); 409 Receiver receiver = mReceivers.get(binder); 410 if (receiver != null) { 411 synchronized (receiver) { 412 // so wakelock calls will succeed 413 long identity = Binder.clearCallingIdentity(); 414 receiver.decrementPendingBroadcastsLocked(); 415 Binder.restoreCallingIdentity(identity); 416 } 417 } 418 } 419 420 private final class SettingsObserver implements Observer { 421 public void update(Observable o, Object arg) { 422 synchronized (mLock) { 423 updateProvidersLocked(); 424 } 425 } 426 } 427 428 private void addProvider(LocationProviderInterface provider) { 429 mProviders.add(provider); 430 mProvidersByName.put(provider.getName(), provider); 431 } 432 433 private void removeProvider(LocationProviderInterface provider) { 434 mProviders.remove(provider); 435 mProvidersByName.remove(provider.getName()); 436 } 437 438 private void loadProviders() { 439 synchronized (mLock) { 440 if (sProvidersLoaded) { 441 return; 442 } 443 444 // Load providers 445 loadProvidersLocked(); 446 sProvidersLoaded = true; 447 } 448 } 449 450 private void loadProvidersLocked() { 451 try { 452 _loadProvidersLocked(); 453 } catch (Exception e) { 454 Slog.e(TAG, "Exception loading providers:", e); 455 } 456 } 457 458 private void _loadProvidersLocked() { 459 // Attempt to load "real" providers first 460 if (GpsLocationProvider.isSupported()) { 461 // Create a gps location provider 462 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this); 463 mGpsStatusProvider = gpsProvider.getGpsStatusProvider(); 464 mNetInitiatedListener = gpsProvider.getNetInitiatedListener(); 465 addProvider(gpsProvider); 466 mGpsLocationProvider = gpsProvider; 467 } 468 469 // create a passive location provider, which is always enabled 470 PassiveProvider passiveProvider = new PassiveProvider(this); 471 addProvider(passiveProvider); 472 mEnabledProviders.add(passiveProvider.getName()); 473 474 // initialize external network location and geocoder services 475 Resources resources = mContext.getResources(); 476 String serviceName = resources.getString( 477 com.android.internal.R.string.config_networkLocationProvider); 478 if (serviceName != null) { 479 mNetworkLocationProvider = 480 new LocationProviderProxy(mContext, LocationManager.NETWORK_PROVIDER, 481 serviceName, mLocationHandler); 482 addProvider(mNetworkLocationProvider); 483 } 484 485 serviceName = resources.getString(com.android.internal.R.string.config_geocodeProvider); 486 if (serviceName != null) { 487 mGeocodeProvider = new GeocoderProxy(mContext, serviceName); 488 } 489 490 updateProvidersLocked(); 491 } 492 493 /** 494 * @param context the context that the LocationManagerService runs in 495 */ 496 public LocationManagerService(Context context) { 497 super(); 498 mContext = context; 499 500 if (LOCAL_LOGV) { 501 Slog.v(TAG, "Constructed LocationManager Service"); 502 } 503 } 504 505 void systemReady() { 506 // we defer starting up the service until the system is ready 507 Thread thread = new Thread(null, this, "LocationManagerService"); 508 thread.start(); 509 } 510 511 private void initialize() { 512 // Create a wake lock, needs to be done before calling loadProviders() below 513 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 514 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); 515 516 // Load providers 517 loadProviders(); 518 519 // Register for Network (Wifi or Mobile) updates 520 IntentFilter intentFilter = new IntentFilter(); 521 intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 522 // Register for Package Manager updates 523 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 524 intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); 525 intentFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); 526 mContext.registerReceiver(mBroadcastReceiver, intentFilter); 527 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 528 mContext.registerReceiver(mBroadcastReceiver, sdFilter); 529 530 // listen for settings changes 531 ContentResolver resolver = mContext.getContentResolver(); 532 Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null, 533 "(" + Settings.System.NAME + "=?)", 534 new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED}, 535 null); 536 mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mLocationHandler); 537 SettingsObserver settingsObserver = new SettingsObserver(); 538 mSettings.addObserver(settingsObserver); 539 } 540 541 public void run() 542 { 543 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 544 Looper.prepare(); 545 mLocationHandler = new LocationWorkerHandler(); 546 initialize(); 547 Looper.loop(); 548 } 549 550 private boolean isAllowedBySettingsLocked(String provider) { 551 if (mEnabledProviders.contains(provider)) { 552 return true; 553 } 554 if (mDisabledProviders.contains(provider)) { 555 return false; 556 } 557 // Use system settings 558 ContentResolver resolver = mContext.getContentResolver(); 559 560 return Settings.Secure.isLocationProviderEnabled(resolver, provider); 561 } 562 563 private void checkPermissionsSafe(String provider) { 564 if ((LocationManager.GPS_PROVIDER.equals(provider) 565 || LocationManager.PASSIVE_PROVIDER.equals(provider)) 566 && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) 567 != PackageManager.PERMISSION_GRANTED)) { 568 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); 569 } 570 if (LocationManager.NETWORK_PROVIDER.equals(provider) 571 && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) 572 != PackageManager.PERMISSION_GRANTED) 573 && (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) 574 != PackageManager.PERMISSION_GRANTED)) { 575 throw new SecurityException( 576 "Requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission"); 577 } 578 } 579 580 private boolean isAllowedProviderSafe(String provider) { 581 if ((LocationManager.GPS_PROVIDER.equals(provider) 582 || LocationManager.PASSIVE_PROVIDER.equals(provider)) 583 && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) 584 != PackageManager.PERMISSION_GRANTED)) { 585 return false; 586 } 587 if (LocationManager.NETWORK_PROVIDER.equals(provider) 588 && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) 589 != PackageManager.PERMISSION_GRANTED) 590 && (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) 591 != PackageManager.PERMISSION_GRANTED)) { 592 return false; 593 } 594 595 return true; 596 } 597 598 public List<String> getAllProviders() { 599 try { 600 synchronized (mLock) { 601 return _getAllProvidersLocked(); 602 } 603 } catch (SecurityException se) { 604 throw se; 605 } catch (Exception e) { 606 Slog.e(TAG, "getAllProviders got exception:", e); 607 return null; 608 } 609 } 610 611 private List<String> _getAllProvidersLocked() { 612 if (LOCAL_LOGV) { 613 Slog.v(TAG, "getAllProviders"); 614 } 615 ArrayList<String> out = new ArrayList<String>(mProviders.size()); 616 for (int i = mProviders.size() - 1; i >= 0; i--) { 617 LocationProviderInterface p = mProviders.get(i); 618 out.add(p.getName()); 619 } 620 return out; 621 } 622 623 public List<String> getProviders(Criteria criteria, boolean enabledOnly) { 624 try { 625 synchronized (mLock) { 626 return _getProvidersLocked(criteria, enabledOnly); 627 } 628 } catch (SecurityException se) { 629 throw se; 630 } catch (Exception e) { 631 Slog.e(TAG, "getProviders got exception:", e); 632 return null; 633 } 634 } 635 636 private List<String> _getProvidersLocked(Criteria criteria, boolean enabledOnly) { 637 if (LOCAL_LOGV) { 638 Slog.v(TAG, "getProviders"); 639 } 640 ArrayList<String> out = new ArrayList<String>(mProviders.size()); 641 for (int i = mProviders.size() - 1; i >= 0; i--) { 642 LocationProviderInterface p = mProviders.get(i); 643 String name = p.getName(); 644 if (isAllowedProviderSafe(name)) { 645 if (enabledOnly && !isAllowedBySettingsLocked(name)) { 646 continue; 647 } 648 if (criteria != null && !p.meetsCriteria(criteria)) { 649 continue; 650 } 651 out.add(name); 652 } 653 } 654 return out; 655 } 656 657 /** 658 * Returns the next looser power requirement, in the sequence: 659 * 660 * POWER_LOW -> POWER_MEDIUM -> POWER_HIGH -> NO_REQUIREMENT 661 */ 662 private int nextPower(int power) { 663 switch (power) { 664 case Criteria.POWER_LOW: 665 return Criteria.POWER_MEDIUM; 666 case Criteria.POWER_MEDIUM: 667 return Criteria.POWER_HIGH; 668 case Criteria.POWER_HIGH: 669 return Criteria.NO_REQUIREMENT; 670 case Criteria.NO_REQUIREMENT: 671 default: 672 return Criteria.NO_REQUIREMENT; 673 } 674 } 675 676 /** 677 * Returns the next looser accuracy requirement, in the sequence: 678 * 679 * ACCURACY_FINE -> ACCURACY_APPROXIMATE-> NO_REQUIREMENT 680 */ 681 private int nextAccuracy(int accuracy) { 682 if (accuracy == Criteria.ACCURACY_FINE) { 683 return Criteria.ACCURACY_COARSE; 684 } else { 685 return Criteria.NO_REQUIREMENT; 686 } 687 } 688 689 private class LpPowerComparator implements Comparator<LocationProviderInterface> { 690 public int compare(LocationProviderInterface l1, LocationProviderInterface l2) { 691 // Smaller is better 692 return (l1.getPowerRequirement() - l2.getPowerRequirement()); 693 } 694 695 public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) { 696 return (l1.getPowerRequirement() == l2.getPowerRequirement()); 697 } 698 } 699 700 private class LpAccuracyComparator implements Comparator<LocationProviderInterface> { 701 public int compare(LocationProviderInterface l1, LocationProviderInterface l2) { 702 // Smaller is better 703 return (l1.getAccuracy() - l2.getAccuracy()); 704 } 705 706 public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) { 707 return (l1.getAccuracy() == l2.getAccuracy()); 708 } 709 } 710 711 private class LpCapabilityComparator implements Comparator<LocationProviderInterface> { 712 713 private static final int ALTITUDE_SCORE = 4; 714 private static final int BEARING_SCORE = 4; 715 private static final int SPEED_SCORE = 4; 716 717 private int score(LocationProviderInterface p) { 718 return (p.supportsAltitude() ? ALTITUDE_SCORE : 0) + 719 (p.supportsBearing() ? BEARING_SCORE : 0) + 720 (p.supportsSpeed() ? SPEED_SCORE : 0); 721 } 722 723 public int compare(LocationProviderInterface l1, LocationProviderInterface l2) { 724 return (score(l2) - score(l1)); // Bigger is better 725 } 726 727 public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) { 728 return (score(l1) == score(l2)); 729 } 730 } 731 732 private LocationProviderInterface best(List<String> providerNames) { 733 ArrayList<LocationProviderInterface> providers; 734 synchronized (mLock) { 735 providers = new ArrayList<LocationProviderInterface>(mProviders.size()); 736 for (int i = mProviders.size() - 1; i >= 0; i--) { 737 providers.add(mProviders.get(i)); 738 } 739 } 740 741 if (providers.size() < 2) { 742 return providers.get(0); 743 } 744 745 // First, sort by power requirement 746 Collections.sort(providers, new LpPowerComparator()); 747 int power = providers.get(0).getPowerRequirement(); 748 if (power < providers.get(1).getPowerRequirement()) { 749 return providers.get(0); 750 } 751 752 int idx, size; 753 754 ArrayList<LocationProviderInterface> tmp = new ArrayList<LocationProviderInterface>(); 755 idx = 0; 756 size = providers.size(); 757 while ((idx < size) && (providers.get(idx).getPowerRequirement() == power)) { 758 tmp.add(providers.get(idx)); 759 idx++; 760 } 761 762 // Next, sort by accuracy 763 Collections.sort(tmp, new LpAccuracyComparator()); 764 int acc = tmp.get(0).getAccuracy(); 765 if (acc < tmp.get(1).getAccuracy()) { 766 return tmp.get(0); 767 } 768 769 ArrayList<LocationProviderInterface> tmp2 = new ArrayList<LocationProviderInterface>(); 770 idx = 0; 771 size = tmp.size(); 772 while ((idx < size) && (tmp.get(idx).getAccuracy() == acc)) { 773 tmp2.add(tmp.get(idx)); 774 idx++; 775 } 776 777 // Finally, sort by capability "score" 778 Collections.sort(tmp2, new LpCapabilityComparator()); 779 return tmp2.get(0); 780 } 781 782 /** 783 * Returns the name of the provider that best meets the given criteria. Only providers 784 * that are permitted to be accessed by the calling activity will be 785 * returned. If several providers meet the criteria, the one with the best 786 * accuracy is returned. If no provider meets the criteria, 787 * the criteria are loosened in the following sequence: 788 * 789 * <ul> 790 * <li> power requirement 791 * <li> accuracy 792 * <li> bearing 793 * <li> speed 794 * <li> altitude 795 * </ul> 796 * 797 * <p> Note that the requirement on monetary cost is not removed 798 * in this process. 799 * 800 * @param criteria the criteria that need to be matched 801 * @param enabledOnly if true then only a provider that is currently enabled is returned 802 * @return name of the provider that best matches the requirements 803 */ 804 public String getBestProvider(Criteria criteria, boolean enabledOnly) { 805 List<String> goodProviders = getProviders(criteria, enabledOnly); 806 if (!goodProviders.isEmpty()) { 807 return best(goodProviders).getName(); 808 } 809 810 // Make a copy of the criteria that we can modify 811 criteria = new Criteria(criteria); 812 813 // Loosen power requirement 814 int power = criteria.getPowerRequirement(); 815 while (goodProviders.isEmpty() && (power != Criteria.NO_REQUIREMENT)) { 816 power = nextPower(power); 817 criteria.setPowerRequirement(power); 818 goodProviders = getProviders(criteria, enabledOnly); 819 } 820 if (!goodProviders.isEmpty()) { 821 return best(goodProviders).getName(); 822 } 823 824 // Loosen accuracy requirement 825 int accuracy = criteria.getAccuracy(); 826 while (goodProviders.isEmpty() && (accuracy != Criteria.NO_REQUIREMENT)) { 827 accuracy = nextAccuracy(accuracy); 828 criteria.setAccuracy(accuracy); 829 goodProviders = getProviders(criteria, enabledOnly); 830 } 831 if (!goodProviders.isEmpty()) { 832 return best(goodProviders).getName(); 833 } 834 835 // Remove bearing requirement 836 criteria.setBearingRequired(false); 837 goodProviders = getProviders(criteria, enabledOnly); 838 if (!goodProviders.isEmpty()) { 839 return best(goodProviders).getName(); 840 } 841 842 // Remove speed requirement 843 criteria.setSpeedRequired(false); 844 goodProviders = getProviders(criteria, enabledOnly); 845 if (!goodProviders.isEmpty()) { 846 return best(goodProviders).getName(); 847 } 848 849 // Remove altitude requirement 850 criteria.setAltitudeRequired(false); 851 goodProviders = getProviders(criteria, enabledOnly); 852 if (!goodProviders.isEmpty()) { 853 return best(goodProviders).getName(); 854 } 855 856 return null; 857 } 858 859 public boolean providerMeetsCriteria(String provider, Criteria criteria) { 860 LocationProviderInterface p = mProvidersByName.get(provider); 861 if (p == null) { 862 throw new IllegalArgumentException("provider=" + provider); 863 } 864 return p.meetsCriteria(criteria); 865 } 866 867 private void updateProvidersLocked() { 868 boolean changesMade = false; 869 for (int i = mProviders.size() - 1; i >= 0; i--) { 870 LocationProviderInterface p = mProviders.get(i); 871 boolean isEnabled = p.isEnabled(); 872 String name = p.getName(); 873 boolean shouldBeEnabled = isAllowedBySettingsLocked(name); 874 if (isEnabled && !shouldBeEnabled) { 875 updateProviderListenersLocked(name, false); 876 changesMade = true; 877 } else if (!isEnabled && shouldBeEnabled) { 878 updateProviderListenersLocked(name, true); 879 changesMade = true; 880 } 881 } 882 if (changesMade) { 883 mContext.sendBroadcast(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION)); 884 } 885 } 886 887 private void updateProviderListenersLocked(String provider, boolean enabled) { 888 int listeners = 0; 889 890 LocationProviderInterface p = mProvidersByName.get(provider); 891 if (p == null) { 892 return; 893 } 894 895 ArrayList<Receiver> deadReceivers = null; 896 897 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 898 if (records != null) { 899 final int N = records.size(); 900 for (int i=0; i<N; i++) { 901 UpdateRecord record = records.get(i); 902 // Sends a notification message to the receiver 903 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) { 904 if (deadReceivers == null) { 905 deadReceivers = new ArrayList<Receiver>(); 906 } 907 deadReceivers.add(record.mReceiver); 908 } 909 listeners++; 910 } 911 } 912 913 if (deadReceivers != null) { 914 for (int i=deadReceivers.size()-1; i>=0; i--) { 915 removeUpdatesLocked(deadReceivers.get(i)); 916 } 917 } 918 919 if (enabled) { 920 p.enable(); 921 if (listeners > 0) { 922 p.setMinTime(getMinTimeLocked(provider), mTmpWorkSource); 923 p.enableLocationTracking(true); 924 } 925 } else { 926 p.enableLocationTracking(false); 927 p.disable(); 928 } 929 } 930 931 private long getMinTimeLocked(String provider) { 932 long minTime = Long.MAX_VALUE; 933 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 934 mTmpWorkSource.clear(); 935 if (records != null) { 936 for (int i=records.size()-1; i>=0; i--) { 937 UpdateRecord ur = records.get(i); 938 long curTime = ur.mMinTime; 939 if (curTime < minTime) { 940 minTime = curTime; 941 } 942 } 943 long inclTime = (minTime*3)/2; 944 for (int i=records.size()-1; i>=0; i--) { 945 UpdateRecord ur = records.get(i); 946 if (ur.mMinTime <= inclTime) { 947 mTmpWorkSource.add(ur.mUid); 948 } 949 } 950 } 951 return minTime; 952 } 953 954 private class UpdateRecord { 955 final String mProvider; 956 final Receiver mReceiver; 957 final long mMinTime; 958 final float mMinDistance; 959 final boolean mSingleShot; 960 final int mUid; 961 Location mLastFixBroadcast; 962 long mLastStatusBroadcast; 963 964 /** 965 * Note: must be constructed with lock held. 966 */ 967 UpdateRecord(String provider, long minTime, float minDistance, boolean singleShot, 968 Receiver receiver, int uid) { 969 mProvider = provider; 970 mReceiver = receiver; 971 mMinTime = minTime; 972 mMinDistance = minDistance; 973 mSingleShot = singleShot; 974 mUid = uid; 975 976 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 977 if (records == null) { 978 records = new ArrayList<UpdateRecord>(); 979 mRecordsByProvider.put(provider, records); 980 } 981 if (!records.contains(this)) { 982 records.add(this); 983 } 984 } 985 986 /** 987 * Method to be called when a record will no longer be used. Calling this multiple times 988 * must have the same effect as calling it once. 989 */ 990 void disposeLocked() { 991 ArrayList<UpdateRecord> records = mRecordsByProvider.get(this.mProvider); 992 if (records != null) { 993 records.remove(this); 994 } 995 } 996 997 @Override 998 public String toString() { 999 return "UpdateRecord{" 1000 + Integer.toHexString(System.identityHashCode(this)) 1001 + " " + mProvider + " " + mReceiver + "}"; 1002 } 1003 1004 void dump(PrintWriter pw, String prefix) { 1005 pw.println(prefix + this); 1006 pw.println(prefix + "mProvider=" + mProvider + " mReceiver=" + mReceiver); 1007 pw.println(prefix + "mMinTime=" + mMinTime + " mMinDistance=" + mMinDistance); 1008 pw.println(prefix + "mSingleShot=" + mSingleShot); 1009 pw.println(prefix + "mUid=" + mUid); 1010 pw.println(prefix + "mLastFixBroadcast:"); 1011 if (mLastFixBroadcast != null) { 1012 mLastFixBroadcast.dump(new PrintWriterPrinter(pw), prefix + " "); 1013 } 1014 pw.println(prefix + "mLastStatusBroadcast=" + mLastStatusBroadcast); 1015 } 1016 } 1017 1018 private Receiver getReceiver(ILocationListener listener) { 1019 IBinder binder = listener.asBinder(); 1020 Receiver receiver = mReceivers.get(binder); 1021 if (receiver == null) { 1022 receiver = new Receiver(listener); 1023 mReceivers.put(binder, receiver); 1024 1025 try { 1026 if (receiver.isListener()) { 1027 receiver.getListener().asBinder().linkToDeath(receiver, 0); 1028 } 1029 } catch (RemoteException e) { 1030 Slog.e(TAG, "linkToDeath failed:", e); 1031 return null; 1032 } 1033 } 1034 return receiver; 1035 } 1036 1037 private Receiver getReceiver(PendingIntent intent) { 1038 Receiver receiver = mReceivers.get(intent); 1039 if (receiver == null) { 1040 receiver = new Receiver(intent); 1041 mReceivers.put(intent, receiver); 1042 } 1043 return receiver; 1044 } 1045 1046 private boolean providerHasListener(String provider, int uid, Receiver excludedReceiver) { 1047 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 1048 if (records != null) { 1049 for (int i = records.size() - 1; i >= 0; i--) { 1050 UpdateRecord record = records.get(i); 1051 if (record.mUid == uid && record.mReceiver != excludedReceiver) { 1052 return true; 1053 } 1054 } 1055 } 1056 for (ProximityAlert alert : mProximityAlerts.values()) { 1057 if (alert.mUid == uid) { 1058 return true; 1059 } 1060 } 1061 return false; 1062 } 1063 1064 public void requestLocationUpdates(String provider, Criteria criteria, 1065 long minTime, float minDistance, boolean singleShot, ILocationListener listener) { 1066 if (criteria != null) { 1067 // FIXME - should we consider using multiple providers simultaneously 1068 // rather than only the best one? 1069 // Should we do anything different for single shot fixes? 1070 provider = getBestProvider(criteria, true); 1071 if (provider == null) { 1072 throw new IllegalArgumentException("no providers found for criteria"); 1073 } 1074 } 1075 try { 1076 synchronized (mLock) { 1077 requestLocationUpdatesLocked(provider, minTime, minDistance, singleShot, 1078 getReceiver(listener)); 1079 } 1080 } catch (SecurityException se) { 1081 throw se; 1082 } catch (IllegalArgumentException iae) { 1083 throw iae; 1084 } catch (Exception e) { 1085 Slog.e(TAG, "requestUpdates got exception:", e); 1086 } 1087 } 1088 1089 public void requestLocationUpdatesPI(String provider, Criteria criteria, 1090 long minTime, float minDistance, boolean singleShot, PendingIntent intent) { 1091 if (criteria != null) { 1092 // FIXME - should we consider using multiple providers simultaneously 1093 // rather than only the best one? 1094 // Should we do anything different for single shot fixes? 1095 provider = getBestProvider(criteria, true); 1096 if (provider == null) { 1097 throw new IllegalArgumentException("no providers found for criteria"); 1098 } 1099 } 1100 try { 1101 synchronized (mLock) { 1102 requestLocationUpdatesLocked(provider, minTime, minDistance, singleShot, 1103 getReceiver(intent)); 1104 } 1105 } catch (SecurityException se) { 1106 throw se; 1107 } catch (IllegalArgumentException iae) { 1108 throw iae; 1109 } catch (Exception e) { 1110 Slog.e(TAG, "requestUpdates got exception:", e); 1111 } 1112 } 1113 1114 private void requestLocationUpdatesLocked(String provider, long minTime, float minDistance, 1115 boolean singleShot, Receiver receiver) { 1116 if (LOCAL_LOGV) { 1117 Slog.v(TAG, "_requestLocationUpdates: listener = " + receiver); 1118 } 1119 1120 LocationProviderInterface p = mProvidersByName.get(provider); 1121 if (p == null) { 1122 throw new IllegalArgumentException("provider=" + provider); 1123 } 1124 1125 checkPermissionsSafe(provider); 1126 1127 // so wakelock calls will succeed 1128 final int callingUid = Binder.getCallingUid(); 1129 boolean newUid = !providerHasListener(provider, callingUid, null); 1130 long identity = Binder.clearCallingIdentity(); 1131 try { 1132 UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, singleShot, 1133 receiver, callingUid); 1134 UpdateRecord oldRecord = receiver.mUpdateRecords.put(provider, r); 1135 if (oldRecord != null) { 1136 oldRecord.disposeLocked(); 1137 } 1138 1139 if (newUid) { 1140 p.addListener(callingUid); 1141 } 1142 1143 boolean isProviderEnabled = isAllowedBySettingsLocked(provider); 1144 if (isProviderEnabled) { 1145 long minTimeForProvider = getMinTimeLocked(provider); 1146 p.setMinTime(minTimeForProvider, mTmpWorkSource); 1147 // try requesting single shot if singleShot is true, and fall back to 1148 // regular location tracking if requestSingleShotFix() is not supported 1149 if (!singleShot || !p.requestSingleShotFix()) { 1150 p.enableLocationTracking(true); 1151 } 1152 } else { 1153 // Notify the listener that updates are currently disabled 1154 receiver.callProviderEnabledLocked(provider, false); 1155 } 1156 } finally { 1157 Binder.restoreCallingIdentity(identity); 1158 } 1159 } 1160 1161 public void removeUpdates(ILocationListener listener) { 1162 try { 1163 synchronized (mLock) { 1164 removeUpdatesLocked(getReceiver(listener)); 1165 } 1166 } catch (SecurityException se) { 1167 throw se; 1168 } catch (IllegalArgumentException iae) { 1169 throw iae; 1170 } catch (Exception e) { 1171 Slog.e(TAG, "removeUpdates got exception:", e); 1172 } 1173 } 1174 1175 public void removeUpdatesPI(PendingIntent intent) { 1176 try { 1177 synchronized (mLock) { 1178 removeUpdatesLocked(getReceiver(intent)); 1179 } 1180 } catch (SecurityException se) { 1181 throw se; 1182 } catch (IllegalArgumentException iae) { 1183 throw iae; 1184 } catch (Exception e) { 1185 Slog.e(TAG, "removeUpdates got exception:", e); 1186 } 1187 } 1188 1189 private void removeUpdatesLocked(Receiver receiver) { 1190 if (LOCAL_LOGV) { 1191 Slog.v(TAG, "_removeUpdates: listener = " + receiver); 1192 } 1193 1194 // so wakelock calls will succeed 1195 final int callingUid = Binder.getCallingUid(); 1196 long identity = Binder.clearCallingIdentity(); 1197 try { 1198 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) { 1199 receiver.getListener().asBinder().unlinkToDeath(receiver, 0); 1200 synchronized(receiver) { 1201 if(receiver.mPendingBroadcasts > 0) { 1202 decrementPendingBroadcasts(); 1203 receiver.mPendingBroadcasts = 0; 1204 } 1205 } 1206 } 1207 1208 // Record which providers were associated with this listener 1209 HashSet<String> providers = new HashSet<String>(); 1210 HashMap<String,UpdateRecord> oldRecords = receiver.mUpdateRecords; 1211 if (oldRecords != null) { 1212 // Call dispose() on the obsolete update records. 1213 for (UpdateRecord record : oldRecords.values()) { 1214 if (!providerHasListener(record.mProvider, callingUid, receiver)) { 1215 LocationProviderInterface p = mProvidersByName.get(record.mProvider); 1216 if (p != null) { 1217 p.removeListener(callingUid); 1218 } 1219 } 1220 record.disposeLocked(); 1221 } 1222 // Accumulate providers 1223 providers.addAll(oldRecords.keySet()); 1224 } 1225 1226 // See if the providers associated with this listener have any 1227 // other listeners; if one does, inform it of the new smallest minTime 1228 // value; if one does not, disable location tracking for it 1229 for (String provider : providers) { 1230 // If provider is already disabled, don't need to do anything 1231 if (!isAllowedBySettingsLocked(provider)) { 1232 continue; 1233 } 1234 1235 boolean hasOtherListener = false; 1236 ArrayList<UpdateRecord> recordsForProvider = mRecordsByProvider.get(provider); 1237 if (recordsForProvider != null && recordsForProvider.size() > 0) { 1238 hasOtherListener = true; 1239 } 1240 1241 LocationProviderInterface p = mProvidersByName.get(provider); 1242 if (p != null) { 1243 if (hasOtherListener) { 1244 p.setMinTime(getMinTimeLocked(provider), mTmpWorkSource); 1245 } else { 1246 p.enableLocationTracking(false); 1247 } 1248 } 1249 } 1250 } finally { 1251 Binder.restoreCallingIdentity(identity); 1252 } 1253 } 1254 1255 public boolean addGpsStatusListener(IGpsStatusListener listener) { 1256 if (mGpsStatusProvider == null) { 1257 return false; 1258 } 1259 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) != 1260 PackageManager.PERMISSION_GRANTED) { 1261 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); 1262 } 1263 1264 try { 1265 mGpsStatusProvider.addGpsStatusListener(listener); 1266 } catch (RemoteException e) { 1267 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e); 1268 return false; 1269 } 1270 return true; 1271 } 1272 1273 public void removeGpsStatusListener(IGpsStatusListener listener) { 1274 synchronized (mLock) { 1275 try { 1276 mGpsStatusProvider.removeGpsStatusListener(listener); 1277 } catch (Exception e) { 1278 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e); 1279 } 1280 } 1281 } 1282 1283 public boolean sendExtraCommand(String provider, String command, Bundle extras) { 1284 if (provider == null) { 1285 // throw NullPointerException to remain compatible with previous implementation 1286 throw new NullPointerException(); 1287 } 1288 1289 // first check for permission to the provider 1290 checkPermissionsSafe(provider); 1291 // and check for ACCESS_LOCATION_EXTRA_COMMANDS 1292 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS) 1293 != PackageManager.PERMISSION_GRANTED)) { 1294 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission"); 1295 } 1296 1297 synchronized (mLock) { 1298 LocationProviderInterface p = mProvidersByName.get(provider); 1299 if (p == null) { 1300 return false; 1301 } 1302 1303 return p.sendExtraCommand(command, extras); 1304 } 1305 } 1306 1307 public boolean sendNiResponse(int notifId, int userResponse) 1308 { 1309 if (Binder.getCallingUid() != Process.myUid()) { 1310 throw new SecurityException( 1311 "calling sendNiResponse from outside of the system is not allowed"); 1312 } 1313 try { 1314 return mNetInitiatedListener.sendNiResponse(notifId, userResponse); 1315 } 1316 catch (RemoteException e) 1317 { 1318 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse"); 1319 return false; 1320 } 1321 } 1322 1323 class ProximityAlert { 1324 final int mUid; 1325 final double mLatitude; 1326 final double mLongitude; 1327 final float mRadius; 1328 final long mExpiration; 1329 final PendingIntent mIntent; 1330 final Location mLocation; 1331 1332 public ProximityAlert(int uid, double latitude, double longitude, 1333 float radius, long expiration, PendingIntent intent) { 1334 mUid = uid; 1335 mLatitude = latitude; 1336 mLongitude = longitude; 1337 mRadius = radius; 1338 mExpiration = expiration; 1339 mIntent = intent; 1340 1341 mLocation = new Location(""); 1342 mLocation.setLatitude(latitude); 1343 mLocation.setLongitude(longitude); 1344 } 1345 1346 long getExpiration() { 1347 return mExpiration; 1348 } 1349 1350 PendingIntent getIntent() { 1351 return mIntent; 1352 } 1353 1354 boolean isInProximity(double latitude, double longitude, float accuracy) { 1355 Location loc = new Location(""); 1356 loc.setLatitude(latitude); 1357 loc.setLongitude(longitude); 1358 1359 double radius = loc.distanceTo(mLocation); 1360 return radius <= Math.max(mRadius,accuracy); 1361 } 1362 1363 @Override 1364 public String toString() { 1365 return "ProximityAlert{" 1366 + Integer.toHexString(System.identityHashCode(this)) 1367 + " uid " + mUid + mIntent + "}"; 1368 } 1369 1370 void dump(PrintWriter pw, String prefix) { 1371 pw.println(prefix + this); 1372 pw.println(prefix + "mLatitude=" + mLatitude + " mLongitude=" + mLongitude); 1373 pw.println(prefix + "mRadius=" + mRadius + " mExpiration=" + mExpiration); 1374 pw.println(prefix + "mIntent=" + mIntent); 1375 pw.println(prefix + "mLocation:"); 1376 mLocation.dump(new PrintWriterPrinter(pw), prefix + " "); 1377 } 1378 } 1379 1380 // Listener for receiving locations to trigger proximity alerts 1381 class ProximityListener extends ILocationListener.Stub implements PendingIntent.OnFinished { 1382 1383 boolean isGpsAvailable = false; 1384 1385 // Note: this is called with the lock held. 1386 public void onLocationChanged(Location loc) { 1387 1388 // If Gps is available, then ignore updates from NetworkLocationProvider 1389 if (loc.getProvider().equals(LocationManager.GPS_PROVIDER)) { 1390 isGpsAvailable = true; 1391 } 1392 if (isGpsAvailable && loc.getProvider().equals(LocationManager.NETWORK_PROVIDER)) { 1393 return; 1394 } 1395 1396 // Process proximity alerts 1397 long now = System.currentTimeMillis(); 1398 double latitude = loc.getLatitude(); 1399 double longitude = loc.getLongitude(); 1400 float accuracy = loc.getAccuracy(); 1401 ArrayList<PendingIntent> intentsToRemove = null; 1402 1403 for (ProximityAlert alert : mProximityAlerts.values()) { 1404 PendingIntent intent = alert.getIntent(); 1405 long expiration = alert.getExpiration(); 1406 1407 if ((expiration == -1) || (now <= expiration)) { 1408 boolean entered = mProximitiesEntered.contains(alert); 1409 boolean inProximity = 1410 alert.isInProximity(latitude, longitude, accuracy); 1411 if (!entered && inProximity) { 1412 if (LOCAL_LOGV) { 1413 Slog.v(TAG, "Entered alert"); 1414 } 1415 mProximitiesEntered.add(alert); 1416 Intent enteredIntent = new Intent(); 1417 enteredIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true); 1418 try { 1419 synchronized (this) { 1420 // synchronize to ensure incrementPendingBroadcasts() 1421 // is called before decrementPendingBroadcasts() 1422 intent.send(mContext, 0, enteredIntent, this, mLocationHandler); 1423 // call this after broadcasting so we do not increment 1424 // if we throw an exeption. 1425 incrementPendingBroadcasts(); 1426 } 1427 } catch (PendingIntent.CanceledException e) { 1428 if (LOCAL_LOGV) { 1429 Slog.v(TAG, "Canceled proximity alert: " + alert, e); 1430 } 1431 if (intentsToRemove == null) { 1432 intentsToRemove = new ArrayList<PendingIntent>(); 1433 } 1434 intentsToRemove.add(intent); 1435 } 1436 } else if (entered && !inProximity) { 1437 if (LOCAL_LOGV) { 1438 Slog.v(TAG, "Exited alert"); 1439 } 1440 mProximitiesEntered.remove(alert); 1441 Intent exitedIntent = new Intent(); 1442 exitedIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false); 1443 try { 1444 synchronized (this) { 1445 // synchronize to ensure incrementPendingBroadcasts() 1446 // is called before decrementPendingBroadcasts() 1447 intent.send(mContext, 0, exitedIntent, this, mLocationHandler); 1448 // call this after broadcasting so we do not increment 1449 // if we throw an exeption. 1450 incrementPendingBroadcasts(); 1451 } 1452 } catch (PendingIntent.CanceledException e) { 1453 if (LOCAL_LOGV) { 1454 Slog.v(TAG, "Canceled proximity alert: " + alert, e); 1455 } 1456 if (intentsToRemove == null) { 1457 intentsToRemove = new ArrayList<PendingIntent>(); 1458 } 1459 intentsToRemove.add(intent); 1460 } 1461 } 1462 } else { 1463 // Mark alert for expiration 1464 if (LOCAL_LOGV) { 1465 Slog.v(TAG, "Expiring proximity alert: " + alert); 1466 } 1467 if (intentsToRemove == null) { 1468 intentsToRemove = new ArrayList<PendingIntent>(); 1469 } 1470 intentsToRemove.add(alert.getIntent()); 1471 } 1472 } 1473 1474 // Remove expired alerts 1475 if (intentsToRemove != null) { 1476 for (PendingIntent i : intentsToRemove) { 1477 ProximityAlert alert = mProximityAlerts.get(i); 1478 mProximitiesEntered.remove(alert); 1479 removeProximityAlertLocked(i); 1480 } 1481 } 1482 } 1483 1484 // Note: this is called with the lock held. 1485 public void onProviderDisabled(String provider) { 1486 if (provider.equals(LocationManager.GPS_PROVIDER)) { 1487 isGpsAvailable = false; 1488 } 1489 } 1490 1491 // Note: this is called with the lock held. 1492 public void onProviderEnabled(String provider) { 1493 // ignore 1494 } 1495 1496 // Note: this is called with the lock held. 1497 public void onStatusChanged(String provider, int status, Bundle extras) { 1498 if ((provider.equals(LocationManager.GPS_PROVIDER)) && 1499 (status != LocationProvider.AVAILABLE)) { 1500 isGpsAvailable = false; 1501 } 1502 } 1503 1504 public void onSendFinished(PendingIntent pendingIntent, Intent intent, 1505 int resultCode, String resultData, Bundle resultExtras) { 1506 // synchronize to ensure incrementPendingBroadcasts() 1507 // is called before decrementPendingBroadcasts() 1508 synchronized (this) { 1509 decrementPendingBroadcasts(); 1510 } 1511 } 1512 } 1513 1514 public void addProximityAlert(double latitude, double longitude, 1515 float radius, long expiration, PendingIntent intent) { 1516 try { 1517 synchronized (mLock) { 1518 addProximityAlertLocked(latitude, longitude, radius, expiration, intent); 1519 } 1520 } catch (SecurityException se) { 1521 throw se; 1522 } catch (IllegalArgumentException iae) { 1523 throw iae; 1524 } catch (Exception e) { 1525 Slog.e(TAG, "addProximityAlert got exception:", e); 1526 } 1527 } 1528 1529 private void addProximityAlertLocked(double latitude, double longitude, 1530 float radius, long expiration, PendingIntent intent) { 1531 if (LOCAL_LOGV) { 1532 Slog.v(TAG, "addProximityAlert: latitude = " + latitude + 1533 ", longitude = " + longitude + 1534 ", expiration = " + expiration + 1535 ", intent = " + intent); 1536 } 1537 1538 // Require ability to access all providers for now 1539 if (!isAllowedProviderSafe(LocationManager.GPS_PROVIDER) || 1540 !isAllowedProviderSafe(LocationManager.NETWORK_PROVIDER)) { 1541 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); 1542 } 1543 1544 if (expiration != -1) { 1545 expiration += System.currentTimeMillis(); 1546 } 1547 ProximityAlert alert = new ProximityAlert(Binder.getCallingUid(), 1548 latitude, longitude, radius, expiration, intent); 1549 mProximityAlerts.put(intent, alert); 1550 1551 if (mProximityReceiver == null) { 1552 mProximityListener = new ProximityListener(); 1553 mProximityReceiver = new Receiver(mProximityListener); 1554 1555 for (int i = mProviders.size() - 1; i >= 0; i--) { 1556 LocationProviderInterface provider = mProviders.get(i); 1557 requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, 1558 false, mProximityReceiver); 1559 } 1560 } 1561 } 1562 1563 public void removeProximityAlert(PendingIntent intent) { 1564 try { 1565 synchronized (mLock) { 1566 removeProximityAlertLocked(intent); 1567 } 1568 } catch (SecurityException se) { 1569 throw se; 1570 } catch (IllegalArgumentException iae) { 1571 throw iae; 1572 } catch (Exception e) { 1573 Slog.e(TAG, "removeProximityAlert got exception:", e); 1574 } 1575 } 1576 1577 private void removeProximityAlertLocked(PendingIntent intent) { 1578 if (LOCAL_LOGV) { 1579 Slog.v(TAG, "removeProximityAlert: intent = " + intent); 1580 } 1581 1582 mProximityAlerts.remove(intent); 1583 if (mProximityAlerts.size() == 0) { 1584 removeUpdatesLocked(mProximityReceiver); 1585 mProximityReceiver = null; 1586 mProximityListener = null; 1587 } 1588 } 1589 1590 /** 1591 * @return null if the provider does not exist 1592 * @throws SecurityException if the provider is not allowed to be 1593 * accessed by the caller 1594 */ 1595 public Bundle getProviderInfo(String provider) { 1596 try { 1597 synchronized (mLock) { 1598 return _getProviderInfoLocked(provider); 1599 } 1600 } catch (SecurityException se) { 1601 throw se; 1602 } catch (IllegalArgumentException iae) { 1603 throw iae; 1604 } catch (Exception e) { 1605 Slog.e(TAG, "_getProviderInfo got exception:", e); 1606 return null; 1607 } 1608 } 1609 1610 private Bundle _getProviderInfoLocked(String provider) { 1611 LocationProviderInterface p = mProvidersByName.get(provider); 1612 if (p == null) { 1613 return null; 1614 } 1615 1616 checkPermissionsSafe(provider); 1617 1618 Bundle b = new Bundle(); 1619 b.putBoolean("network", p.requiresNetwork()); 1620 b.putBoolean("satellite", p.requiresSatellite()); 1621 b.putBoolean("cell", p.requiresCell()); 1622 b.putBoolean("cost", p.hasMonetaryCost()); 1623 b.putBoolean("altitude", p.supportsAltitude()); 1624 b.putBoolean("speed", p.supportsSpeed()); 1625 b.putBoolean("bearing", p.supportsBearing()); 1626 b.putInt("power", p.getPowerRequirement()); 1627 b.putInt("accuracy", p.getAccuracy()); 1628 1629 return b; 1630 } 1631 1632 public boolean isProviderEnabled(String provider) { 1633 try { 1634 synchronized (mLock) { 1635 return _isProviderEnabledLocked(provider); 1636 } 1637 } catch (SecurityException se) { 1638 throw se; 1639 } catch (Exception e) { 1640 Slog.e(TAG, "isProviderEnabled got exception:", e); 1641 return false; 1642 } 1643 } 1644 1645 public void reportLocation(Location location, boolean passive) { 1646 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER) 1647 != PackageManager.PERMISSION_GRANTED) { 1648 throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission"); 1649 } 1650 1651 mLocationHandler.removeMessages(MESSAGE_LOCATION_CHANGED, location); 1652 Message m = Message.obtain(mLocationHandler, MESSAGE_LOCATION_CHANGED, location); 1653 m.arg1 = (passive ? 1 : 0); 1654 mLocationHandler.sendMessageAtFrontOfQueue(m); 1655 } 1656 1657 private boolean _isProviderEnabledLocked(String provider) { 1658 checkPermissionsSafe(provider); 1659 1660 LocationProviderInterface p = mProvidersByName.get(provider); 1661 if (p == null) { 1662 return false; 1663 } 1664 return isAllowedBySettingsLocked(provider); 1665 } 1666 1667 public Location getLastKnownLocation(String provider) { 1668 try { 1669 synchronized (mLock) { 1670 return _getLastKnownLocationLocked(provider); 1671 } 1672 } catch (SecurityException se) { 1673 throw se; 1674 } catch (Exception e) { 1675 Slog.e(TAG, "getLastKnownLocation got exception:", e); 1676 return null; 1677 } 1678 } 1679 1680 private Location _getLastKnownLocationLocked(String provider) { 1681 checkPermissionsSafe(provider); 1682 1683 LocationProviderInterface p = mProvidersByName.get(provider); 1684 if (p == null) { 1685 return null; 1686 } 1687 1688 if (!isAllowedBySettingsLocked(provider)) { 1689 return null; 1690 } 1691 1692 return mLastKnownLocation.get(provider); 1693 } 1694 1695 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) { 1696 // Always broadcast the first update 1697 if (lastLoc == null) { 1698 return true; 1699 } 1700 1701 // Don't broadcast same location again regardless of condition 1702 // TODO - we should probably still rebroadcast if user explicitly sets a minTime > 0 1703 if (loc.getTime() == lastLoc.getTime()) { 1704 return false; 1705 } 1706 1707 // Check whether sufficient distance has been traveled 1708 double minDistance = record.mMinDistance; 1709 if (minDistance > 0.0) { 1710 if (loc.distanceTo(lastLoc) <= minDistance) { 1711 return false; 1712 } 1713 } 1714 1715 return true; 1716 } 1717 1718 private void handleLocationChangedLocked(Location location, boolean passive) { 1719 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider()); 1720 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 1721 if (records == null || records.size() == 0) { 1722 return; 1723 } 1724 1725 LocationProviderInterface p = mProvidersByName.get(provider); 1726 if (p == null) { 1727 return; 1728 } 1729 1730 // Update last known location for provider 1731 Location lastLocation = mLastKnownLocation.get(provider); 1732 if (lastLocation == null) { 1733 mLastKnownLocation.put(provider, new Location(location)); 1734 } else { 1735 lastLocation.set(location); 1736 } 1737 1738 // Fetch latest status update time 1739 long newStatusUpdateTime = p.getStatusUpdateTime(); 1740 1741 // Get latest status 1742 Bundle extras = new Bundle(); 1743 int status = p.getStatus(extras); 1744 1745 ArrayList<Receiver> deadReceivers = null; 1746 1747 // Broadcast location or status to all listeners 1748 final int N = records.size(); 1749 for (int i=0; i<N; i++) { 1750 UpdateRecord r = records.get(i); 1751 Receiver receiver = r.mReceiver; 1752 boolean receiverDead = false; 1753 1754 Location lastLoc = r.mLastFixBroadcast; 1755 if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) { 1756 if (lastLoc == null) { 1757 lastLoc = new Location(location); 1758 r.mLastFixBroadcast = lastLoc; 1759 } else { 1760 lastLoc.set(location); 1761 } 1762 if (!receiver.callLocationChangedLocked(location)) { 1763 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver); 1764 receiverDead = true; 1765 } 1766 } 1767 1768 long prevStatusUpdateTime = r.mLastStatusBroadcast; 1769 if ((newStatusUpdateTime > prevStatusUpdateTime) && 1770 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) { 1771 1772 r.mLastStatusBroadcast = newStatusUpdateTime; 1773 if (!receiver.callStatusChangedLocked(provider, status, extras)) { 1774 receiverDead = true; 1775 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver); 1776 } 1777 } 1778 1779 // remove receiver if it is dead or we just processed a single shot request 1780 if (receiverDead || r.mSingleShot) { 1781 if (deadReceivers == null) { 1782 deadReceivers = new ArrayList<Receiver>(); 1783 } 1784 if (!deadReceivers.contains(receiver)) { 1785 deadReceivers.add(receiver); 1786 } 1787 } 1788 } 1789 1790 if (deadReceivers != null) { 1791 for (int i=deadReceivers.size()-1; i>=0; i--) { 1792 removeUpdatesLocked(deadReceivers.get(i)); 1793 } 1794 } 1795 } 1796 1797 private class LocationWorkerHandler extends Handler { 1798 1799 @Override 1800 public void handleMessage(Message msg) { 1801 try { 1802 if (msg.what == MESSAGE_LOCATION_CHANGED) { 1803 // log("LocationWorkerHandler: MESSAGE_LOCATION_CHANGED!"); 1804 1805 synchronized (mLock) { 1806 Location location = (Location) msg.obj; 1807 String provider = location.getProvider(); 1808 boolean passive = (msg.arg1 == 1); 1809 1810 if (!passive) { 1811 // notify other providers of the new location 1812 for (int i = mProviders.size() - 1; i >= 0; i--) { 1813 LocationProviderInterface p = mProviders.get(i); 1814 if (!provider.equals(p.getName())) { 1815 p.updateLocation(location); 1816 } 1817 } 1818 } 1819 1820 if (isAllowedBySettingsLocked(provider)) { 1821 handleLocationChangedLocked(location, passive); 1822 } 1823 } 1824 } 1825 } catch (Exception e) { 1826 // Log, don't crash! 1827 Slog.e(TAG, "Exception in LocationWorkerHandler.handleMessage:", e); 1828 } 1829 } 1830 } 1831 1832 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 1833 @Override 1834 public void onReceive(Context context, Intent intent) { 1835 String action = intent.getAction(); 1836 boolean queryRestart = action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART); 1837 if (queryRestart 1838 || action.equals(Intent.ACTION_PACKAGE_REMOVED) 1839 || action.equals(Intent.ACTION_PACKAGE_RESTARTED) 1840 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { 1841 synchronized (mLock) { 1842 int uidList[] = null; 1843 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { 1844 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 1845 } else { 1846 uidList = new int[]{intent.getIntExtra(Intent.EXTRA_UID, -1)}; 1847 } 1848 if (uidList == null || uidList.length == 0) { 1849 return; 1850 } 1851 for (int uid : uidList) { 1852 if (uid >= 0) { 1853 ArrayList<Receiver> removedRecs = null; 1854 for (ArrayList<UpdateRecord> i : mRecordsByProvider.values()) { 1855 for (int j=i.size()-1; j>=0; j--) { 1856 UpdateRecord ur = i.get(j); 1857 if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) { 1858 if (queryRestart) { 1859 setResultCode(Activity.RESULT_OK); 1860 return; 1861 } 1862 if (removedRecs == null) { 1863 removedRecs = new ArrayList<Receiver>(); 1864 } 1865 if (!removedRecs.contains(ur.mReceiver)) { 1866 removedRecs.add(ur.mReceiver); 1867 } 1868 } 1869 } 1870 } 1871 ArrayList<ProximityAlert> removedAlerts = null; 1872 for (ProximityAlert i : mProximityAlerts.values()) { 1873 if (i.mUid == uid) { 1874 if (queryRestart) { 1875 setResultCode(Activity.RESULT_OK); 1876 return; 1877 } 1878 if (removedAlerts == null) { 1879 removedAlerts = new ArrayList<ProximityAlert>(); 1880 } 1881 if (!removedAlerts.contains(i)) { 1882 removedAlerts.add(i); 1883 } 1884 } 1885 } 1886 if (removedRecs != null) { 1887 for (int i=removedRecs.size()-1; i>=0; i--) { 1888 removeUpdatesLocked(removedRecs.get(i)); 1889 } 1890 } 1891 if (removedAlerts != null) { 1892 for (int i=removedAlerts.size()-1; i>=0; i--) { 1893 removeProximityAlertLocked(removedAlerts.get(i).mIntent); 1894 } 1895 } 1896 } 1897 } 1898 } 1899 } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 1900 boolean noConnectivity = 1901 intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); 1902 if (!noConnectivity) { 1903 mNetworkState = LocationProvider.AVAILABLE; 1904 } else { 1905 mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE; 1906 } 1907 NetworkInfo info = 1908 (NetworkInfo)intent.getExtra(ConnectivityManager.EXTRA_NETWORK_INFO); 1909 1910 // Notify location providers of current network state 1911 synchronized (mLock) { 1912 for (int i = mProviders.size() - 1; i >= 0; i--) { 1913 LocationProviderInterface provider = mProviders.get(i); 1914 if (provider.requiresNetwork()) { 1915 provider.updateNetworkState(mNetworkState, info); 1916 } 1917 } 1918 } 1919 } 1920 } 1921 }; 1922 1923 // Wake locks 1924 1925 private void incrementPendingBroadcasts() { 1926 synchronized (mWakeLock) { 1927 if (mPendingBroadcasts++ == 0) { 1928 try { 1929 mWakeLock.acquire(); 1930 log("Acquired wakelock"); 1931 } catch (Exception e) { 1932 // This is to catch a runtime exception thrown when we try to release an 1933 // already released lock. 1934 Slog.e(TAG, "exception in acquireWakeLock()", e); 1935 } 1936 } 1937 } 1938 } 1939 1940 private void decrementPendingBroadcasts() { 1941 synchronized (mWakeLock) { 1942 if (--mPendingBroadcasts == 0) { 1943 try { 1944 // Release wake lock 1945 if (mWakeLock.isHeld()) { 1946 mWakeLock.release(); 1947 log("Released wakelock"); 1948 } else { 1949 log("Can't release wakelock again!"); 1950 } 1951 } catch (Exception e) { 1952 // This is to catch a runtime exception thrown when we try to release an 1953 // already released lock. 1954 Slog.e(TAG, "exception in releaseWakeLock()", e); 1955 } 1956 } 1957 } 1958 } 1959 1960 // Geocoder 1961 1962 public boolean geocoderIsImplemented() { 1963 return mGeocodeProvider != null; 1964 } 1965 1966 public String getFromLocation(double latitude, double longitude, int maxResults, 1967 GeocoderParams params, List<Address> addrs) { 1968 if (mGeocodeProvider != null) { 1969 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, 1970 params, addrs); 1971 } 1972 return null; 1973 } 1974 1975 1976 public String getFromLocationName(String locationName, 1977 double lowerLeftLatitude, double lowerLeftLongitude, 1978 double upperRightLatitude, double upperRightLongitude, int maxResults, 1979 GeocoderParams params, List<Address> addrs) { 1980 1981 if (mGeocodeProvider != null) { 1982 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude, 1983 lowerLeftLongitude, upperRightLatitude, upperRightLongitude, 1984 maxResults, params, addrs); 1985 } 1986 return null; 1987 } 1988 1989 // Mock Providers 1990 1991 private void checkMockPermissionsSafe() { 1992 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(), 1993 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1; 1994 if (!allowMocks) { 1995 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting"); 1996 } 1997 1998 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) != 1999 PackageManager.PERMISSION_GRANTED) { 2000 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission"); 2001 } 2002 } 2003 2004 public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite, 2005 boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, 2006 boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) { 2007 checkMockPermissionsSafe(); 2008 2009 if (LocationManager.PASSIVE_PROVIDER.equals(name)) { 2010 throw new IllegalArgumentException("Cannot mock the passive location provider"); 2011 } 2012 2013 long identity = Binder.clearCallingIdentity(); 2014 synchronized (mLock) { 2015 MockProvider provider = new MockProvider(name, this, 2016 requiresNetwork, requiresSatellite, 2017 requiresCell, hasMonetaryCost, supportsAltitude, 2018 supportsSpeed, supportsBearing, powerRequirement, accuracy); 2019 // remove the real provider if we are replacing GPS or network provider 2020 if (LocationManager.GPS_PROVIDER.equals(name) 2021 || LocationManager.NETWORK_PROVIDER.equals(name)) { 2022 LocationProviderInterface p = mProvidersByName.get(name); 2023 if (p != null) { 2024 p.enableLocationTracking(false); 2025 removeProvider(p); 2026 } 2027 } 2028 if (mProvidersByName.get(name) != null) { 2029 throw new IllegalArgumentException("Provider \"" + name + "\" already exists"); 2030 } 2031 addProvider(provider); 2032 mMockProviders.put(name, provider); 2033 mLastKnownLocation.put(name, null); 2034 updateProvidersLocked(); 2035 } 2036 Binder.restoreCallingIdentity(identity); 2037 } 2038 2039 public void removeTestProvider(String provider) { 2040 checkMockPermissionsSafe(); 2041 synchronized (mLock) { 2042 MockProvider mockProvider = mMockProviders.get(provider); 2043 if (mockProvider == null) { 2044 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2045 } 2046 long identity = Binder.clearCallingIdentity(); 2047 removeProvider(mProvidersByName.get(provider)); 2048 mMockProviders.remove(mockProvider); 2049 // reinstall real provider if we were mocking GPS or network provider 2050 if (LocationManager.GPS_PROVIDER.equals(provider) && 2051 mGpsLocationProvider != null) { 2052 addProvider(mGpsLocationProvider); 2053 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) && 2054 mNetworkLocationProvider != null) { 2055 addProvider(mNetworkLocationProvider); 2056 } 2057 mLastKnownLocation.put(provider, null); 2058 updateProvidersLocked(); 2059 Binder.restoreCallingIdentity(identity); 2060 } 2061 } 2062 2063 public void setTestProviderLocation(String provider, Location loc) { 2064 checkMockPermissionsSafe(); 2065 synchronized (mLock) { 2066 MockProvider mockProvider = mMockProviders.get(provider); 2067 if (mockProvider == null) { 2068 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2069 } 2070 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required 2071 long identity = Binder.clearCallingIdentity(); 2072 mockProvider.setLocation(loc); 2073 Binder.restoreCallingIdentity(identity); 2074 } 2075 } 2076 2077 public void clearTestProviderLocation(String provider) { 2078 checkMockPermissionsSafe(); 2079 synchronized (mLock) { 2080 MockProvider mockProvider = mMockProviders.get(provider); 2081 if (mockProvider == null) { 2082 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2083 } 2084 mockProvider.clearLocation(); 2085 } 2086 } 2087 2088 public void setTestProviderEnabled(String provider, boolean enabled) { 2089 checkMockPermissionsSafe(); 2090 synchronized (mLock) { 2091 MockProvider mockProvider = mMockProviders.get(provider); 2092 if (mockProvider == null) { 2093 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2094 } 2095 long identity = Binder.clearCallingIdentity(); 2096 if (enabled) { 2097 mockProvider.enable(); 2098 mEnabledProviders.add(provider); 2099 mDisabledProviders.remove(provider); 2100 } else { 2101 mockProvider.disable(); 2102 mEnabledProviders.remove(provider); 2103 mDisabledProviders.add(provider); 2104 } 2105 updateProvidersLocked(); 2106 Binder.restoreCallingIdentity(identity); 2107 } 2108 } 2109 2110 public void clearTestProviderEnabled(String provider) { 2111 checkMockPermissionsSafe(); 2112 synchronized (mLock) { 2113 MockProvider mockProvider = mMockProviders.get(provider); 2114 if (mockProvider == null) { 2115 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2116 } 2117 long identity = Binder.clearCallingIdentity(); 2118 mEnabledProviders.remove(provider); 2119 mDisabledProviders.remove(provider); 2120 updateProvidersLocked(); 2121 Binder.restoreCallingIdentity(identity); 2122 } 2123 } 2124 2125 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) { 2126 checkMockPermissionsSafe(); 2127 synchronized (mLock) { 2128 MockProvider mockProvider = mMockProviders.get(provider); 2129 if (mockProvider == null) { 2130 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2131 } 2132 mockProvider.setStatus(status, extras, updateTime); 2133 } 2134 } 2135 2136 public void clearTestProviderStatus(String provider) { 2137 checkMockPermissionsSafe(); 2138 synchronized (mLock) { 2139 MockProvider mockProvider = mMockProviders.get(provider); 2140 if (mockProvider == null) { 2141 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2142 } 2143 mockProvider.clearStatus(); 2144 } 2145 } 2146 2147 private void log(String log) { 2148 if (Log.isLoggable(TAG, Log.VERBOSE)) { 2149 Slog.d(TAG, log); 2150 } 2151 } 2152 2153 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2154 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 2155 != PackageManager.PERMISSION_GRANTED) { 2156 pw.println("Permission Denial: can't dump LocationManagerService from from pid=" 2157 + Binder.getCallingPid() 2158 + ", uid=" + Binder.getCallingUid()); 2159 return; 2160 } 2161 2162 synchronized (mLock) { 2163 pw.println("Current Location Manager state:"); 2164 pw.println(" sProvidersLoaded=" + sProvidersLoaded); 2165 pw.println(" Listeners:"); 2166 int N = mReceivers.size(); 2167 for (int i=0; i<N; i++) { 2168 pw.println(" " + mReceivers.get(i)); 2169 } 2170 pw.println(" Location Listeners:"); 2171 for (Receiver i : mReceivers.values()) { 2172 pw.println(" " + i + ":"); 2173 for (Map.Entry<String,UpdateRecord> j : i.mUpdateRecords.entrySet()) { 2174 pw.println(" " + j.getKey() + ":"); 2175 j.getValue().dump(pw, " "); 2176 } 2177 } 2178 pw.println(" Records by Provider:"); 2179 for (Map.Entry<String, ArrayList<UpdateRecord>> i 2180 : mRecordsByProvider.entrySet()) { 2181 pw.println(" " + i.getKey() + ":"); 2182 for (UpdateRecord j : i.getValue()) { 2183 pw.println(" " + j + ":"); 2184 j.dump(pw, " "); 2185 } 2186 } 2187 pw.println(" Last Known Locations:"); 2188 for (Map.Entry<String, Location> i 2189 : mLastKnownLocation.entrySet()) { 2190 pw.println(" " + i.getKey() + ":"); 2191 i.getValue().dump(new PrintWriterPrinter(pw), " "); 2192 } 2193 if (mProximityAlerts.size() > 0) { 2194 pw.println(" Proximity Alerts:"); 2195 for (Map.Entry<PendingIntent, ProximityAlert> i 2196 : mProximityAlerts.entrySet()) { 2197 pw.println(" " + i.getKey() + ":"); 2198 i.getValue().dump(pw, " "); 2199 } 2200 } 2201 if (mProximitiesEntered.size() > 0) { 2202 pw.println(" Proximities Entered:"); 2203 for (ProximityAlert i : mProximitiesEntered) { 2204 pw.println(" " + i + ":"); 2205 i.dump(pw, " "); 2206 } 2207 } 2208 pw.println(" mProximityReceiver=" + mProximityReceiver); 2209 pw.println(" mProximityListener=" + mProximityListener); 2210 if (mEnabledProviders.size() > 0) { 2211 pw.println(" Enabled Providers:"); 2212 for (String i : mEnabledProviders) { 2213 pw.println(" " + i); 2214 } 2215 2216 } 2217 if (mDisabledProviders.size() > 0) { 2218 pw.println(" Disabled Providers:"); 2219 for (String i : mDisabledProviders) { 2220 pw.println(" " + i); 2221 } 2222 2223 } 2224 if (mMockProviders.size() > 0) { 2225 pw.println(" Mock Providers:"); 2226 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) { 2227 i.getValue().dump(pw, " "); 2228 } 2229 } 2230 for (LocationProviderInterface provider: mProviders) { 2231 String state = provider.getInternalState(); 2232 if (state != null) { 2233 pw.println(provider.getName() + " Internal State:"); 2234 pw.write(state); 2235 } 2236 } 2237 } 2238 } 2239} 2240