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