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