LocationManagerService.java revision 2d4d1bf14b531de9d4238b1e41b53c77f8976405
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 = true; 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("Requires ACCESS_FINE_LOCATION permission"); 578 } 579 if (LocationManager.NETWORK_PROVIDER.equals(provider) 580 && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) 581 != PackageManager.PERMISSION_GRANTED) 582 && (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) 583 != PackageManager.PERMISSION_GRANTED)) { 584 throw new SecurityException( 585 "Requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission"); 586 } 587 } 588 589 private boolean isAllowedProviderSafe(String provider) { 590 if ((LocationManager.GPS_PROVIDER.equals(provider) 591 || LocationManager.PASSIVE_PROVIDER.equals(provider)) 592 && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) 593 != PackageManager.PERMISSION_GRANTED)) { 594 return false; 595 } 596 if (LocationManager.NETWORK_PROVIDER.equals(provider) 597 && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) 598 != PackageManager.PERMISSION_GRANTED) 599 && (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) 600 != PackageManager.PERMISSION_GRANTED)) { 601 return false; 602 } 603 604 return true; 605 } 606 607 public List<String> getAllProviders() { 608 try { 609 synchronized (mLock) { 610 return _getAllProvidersLocked(); 611 } 612 } catch (SecurityException se) { 613 throw se; 614 } catch (Exception e) { 615 Slog.e(TAG, "getAllProviders got exception:", e); 616 return null; 617 } 618 } 619 620 private List<String> _getAllProvidersLocked() { 621 if (LOCAL_LOGV) { 622 Slog.v(TAG, "getAllProviders"); 623 } 624 ArrayList<String> out = new ArrayList<String>(mProviders.size()); 625 for (int i = mProviders.size() - 1; i >= 0; i--) { 626 LocationProviderInterface p = mProviders.get(i); 627 out.add(p.getName()); 628 } 629 return out; 630 } 631 632 public List<String> getProviders(Criteria criteria, boolean enabledOnly) { 633 try { 634 synchronized (mLock) { 635 return _getProvidersLocked(criteria, enabledOnly); 636 } 637 } catch (SecurityException se) { 638 throw se; 639 } catch (Exception e) { 640 Slog.e(TAG, "getProviders got exception:", e); 641 return null; 642 } 643 } 644 645 private List<String> _getProvidersLocked(Criteria criteria, boolean enabledOnly) { 646 if (LOCAL_LOGV) { 647 Slog.v(TAG, "getProviders"); 648 } 649 ArrayList<String> out = new ArrayList<String>(mProviders.size()); 650 for (int i = mProviders.size() - 1; i >= 0; i--) { 651 LocationProviderInterface p = mProviders.get(i); 652 String name = p.getName(); 653 if (isAllowedProviderSafe(name)) { 654 if (enabledOnly && !isAllowedBySettingsLocked(name)) { 655 continue; 656 } 657 if (criteria != null && !p.meetsCriteria(criteria)) { 658 continue; 659 } 660 out.add(name); 661 } 662 } 663 return out; 664 } 665 666 /** 667 * Returns the next looser power requirement, in the sequence: 668 * 669 * POWER_LOW -> POWER_MEDIUM -> POWER_HIGH -> NO_REQUIREMENT 670 */ 671 private int nextPower(int power) { 672 switch (power) { 673 case Criteria.POWER_LOW: 674 return Criteria.POWER_MEDIUM; 675 case Criteria.POWER_MEDIUM: 676 return Criteria.POWER_HIGH; 677 case Criteria.POWER_HIGH: 678 return Criteria.NO_REQUIREMENT; 679 case Criteria.NO_REQUIREMENT: 680 default: 681 return Criteria.NO_REQUIREMENT; 682 } 683 } 684 685 /** 686 * Returns the next looser accuracy requirement, in the sequence: 687 * 688 * ACCURACY_FINE -> ACCURACY_APPROXIMATE-> NO_REQUIREMENT 689 */ 690 private int nextAccuracy(int accuracy) { 691 if (accuracy == Criteria.ACCURACY_FINE) { 692 return Criteria.ACCURACY_COARSE; 693 } else { 694 return Criteria.NO_REQUIREMENT; 695 } 696 } 697 698 private class LpPowerComparator implements Comparator<LocationProviderInterface> { 699 public int compare(LocationProviderInterface l1, LocationProviderInterface l2) { 700 // Smaller is better 701 return (l1.getPowerRequirement() - l2.getPowerRequirement()); 702 } 703 704 public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) { 705 return (l1.getPowerRequirement() == l2.getPowerRequirement()); 706 } 707 } 708 709 private class LpAccuracyComparator implements Comparator<LocationProviderInterface> { 710 public int compare(LocationProviderInterface l1, LocationProviderInterface l2) { 711 // Smaller is better 712 return (l1.getAccuracy() - l2.getAccuracy()); 713 } 714 715 public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) { 716 return (l1.getAccuracy() == l2.getAccuracy()); 717 } 718 } 719 720 private class LpCapabilityComparator implements Comparator<LocationProviderInterface> { 721 722 private static final int ALTITUDE_SCORE = 4; 723 private static final int BEARING_SCORE = 4; 724 private static final int SPEED_SCORE = 4; 725 726 private int score(LocationProviderInterface p) { 727 return (p.supportsAltitude() ? ALTITUDE_SCORE : 0) + 728 (p.supportsBearing() ? BEARING_SCORE : 0) + 729 (p.supportsSpeed() ? SPEED_SCORE : 0); 730 } 731 732 public int compare(LocationProviderInterface l1, LocationProviderInterface l2) { 733 return (score(l2) - score(l1)); // Bigger is better 734 } 735 736 public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) { 737 return (score(l1) == score(l2)); 738 } 739 } 740 741 private LocationProviderInterface best(List<String> providerNames) { 742 ArrayList<LocationProviderInterface> providers; 743 synchronized (mLock) { 744 providers = new ArrayList<LocationProviderInterface>(mProviders.size()); 745 for (int i = mProviders.size() - 1; i >= 0; i--) { 746 providers.add(mProviders.get(i)); 747 } 748 } 749 750 if (providers.size() < 2) { 751 return providers.get(0); 752 } 753 754 // First, sort by power requirement 755 Collections.sort(providers, new LpPowerComparator()); 756 int power = providers.get(0).getPowerRequirement(); 757 if (power < providers.get(1).getPowerRequirement()) { 758 return providers.get(0); 759 } 760 761 int idx, size; 762 763 ArrayList<LocationProviderInterface> tmp = new ArrayList<LocationProviderInterface>(); 764 idx = 0; 765 size = providers.size(); 766 while ((idx < size) && (providers.get(idx).getPowerRequirement() == power)) { 767 tmp.add(providers.get(idx)); 768 idx++; 769 } 770 771 // Next, sort by accuracy 772 Collections.sort(tmp, new LpAccuracyComparator()); 773 int acc = tmp.get(0).getAccuracy(); 774 if (acc < tmp.get(1).getAccuracy()) { 775 return tmp.get(0); 776 } 777 778 ArrayList<LocationProviderInterface> tmp2 = new ArrayList<LocationProviderInterface>(); 779 idx = 0; 780 size = tmp.size(); 781 while ((idx < size) && (tmp.get(idx).getAccuracy() == acc)) { 782 tmp2.add(tmp.get(idx)); 783 idx++; 784 } 785 786 // Finally, sort by capability "score" 787 Collections.sort(tmp2, new LpCapabilityComparator()); 788 return tmp2.get(0); 789 } 790 791 /** 792 * Returns the name of the provider that best meets the given criteria. Only providers 793 * that are permitted to be accessed by the calling activity will be 794 * returned. If several providers meet the criteria, the one with the best 795 * accuracy is returned. If no provider meets the criteria, 796 * the criteria are loosened in the following sequence: 797 * 798 * <ul> 799 * <li> power requirement 800 * <li> accuracy 801 * <li> bearing 802 * <li> speed 803 * <li> altitude 804 * </ul> 805 * 806 * <p> Note that the requirement on monetary cost is not removed 807 * in this process. 808 * 809 * @param criteria the criteria that need to be matched 810 * @param enabledOnly if true then only a provider that is currently enabled is returned 811 * @return name of the provider that best matches the requirements 812 */ 813 public String getBestProvider(Criteria criteria, boolean enabledOnly) { 814 List<String> goodProviders = getProviders(criteria, enabledOnly); 815 if (!goodProviders.isEmpty()) { 816 return best(goodProviders).getName(); 817 } 818 819 // Make a copy of the criteria that we can modify 820 criteria = new Criteria(criteria); 821 822 // Loosen power requirement 823 int power = criteria.getPowerRequirement(); 824 while (goodProviders.isEmpty() && (power != Criteria.NO_REQUIREMENT)) { 825 power = nextPower(power); 826 criteria.setPowerRequirement(power); 827 goodProviders = getProviders(criteria, enabledOnly); 828 } 829 if (!goodProviders.isEmpty()) { 830 return best(goodProviders).getName(); 831 } 832 833 // Loosen accuracy requirement 834 int accuracy = criteria.getAccuracy(); 835 while (goodProviders.isEmpty() && (accuracy != Criteria.NO_REQUIREMENT)) { 836 accuracy = nextAccuracy(accuracy); 837 criteria.setAccuracy(accuracy); 838 goodProviders = getProviders(criteria, enabledOnly); 839 } 840 if (!goodProviders.isEmpty()) { 841 return best(goodProviders).getName(); 842 } 843 844 // Remove bearing requirement 845 criteria.setBearingRequired(false); 846 goodProviders = getProviders(criteria, enabledOnly); 847 if (!goodProviders.isEmpty()) { 848 return best(goodProviders).getName(); 849 } 850 851 // Remove speed requirement 852 criteria.setSpeedRequired(false); 853 goodProviders = getProviders(criteria, enabledOnly); 854 if (!goodProviders.isEmpty()) { 855 return best(goodProviders).getName(); 856 } 857 858 // Remove altitude requirement 859 criteria.setAltitudeRequired(false); 860 goodProviders = getProviders(criteria, enabledOnly); 861 if (!goodProviders.isEmpty()) { 862 return best(goodProviders).getName(); 863 } 864 865 return null; 866 } 867 868 public boolean providerMeetsCriteria(String provider, Criteria criteria) { 869 LocationProviderInterface p = mProvidersByName.get(provider); 870 if (p == null) { 871 throw new IllegalArgumentException("provider=" + provider); 872 } 873 return p.meetsCriteria(criteria); 874 } 875 876 private void updateProvidersLocked() { 877 boolean changesMade = false; 878 for (int i = mProviders.size() - 1; i >= 0; i--) { 879 LocationProviderInterface p = mProviders.get(i); 880 boolean isEnabled = p.isEnabled(); 881 String name = p.getName(); 882 boolean shouldBeEnabled = isAllowedBySettingsLocked(name); 883 if (isEnabled && !shouldBeEnabled) { 884 updateProviderListenersLocked(name, false); 885 changesMade = true; 886 } else if (!isEnabled && shouldBeEnabled) { 887 updateProviderListenersLocked(name, true); 888 changesMade = true; 889 } 890 } 891 if (changesMade) { 892 mContext.sendBroadcast(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION)); 893 } 894 } 895 896 private void updateProviderListenersLocked(String provider, boolean enabled) { 897 int listeners = 0; 898 899 LocationProviderInterface p = mProvidersByName.get(provider); 900 if (p == null) { 901 return; 902 } 903 904 ArrayList<Receiver> deadReceivers = null; 905 906 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 907 if (records != null) { 908 final int N = records.size(); 909 for (int i=0; i<N; i++) { 910 UpdateRecord record = records.get(i); 911 // Sends a notification message to the receiver 912 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) { 913 if (deadReceivers == null) { 914 deadReceivers = new ArrayList<Receiver>(); 915 } 916 deadReceivers.add(record.mReceiver); 917 } 918 listeners++; 919 } 920 } 921 922 if (deadReceivers != null) { 923 for (int i=deadReceivers.size()-1; i>=0; i--) { 924 removeUpdatesLocked(deadReceivers.get(i)); 925 } 926 } 927 928 if (enabled) { 929 p.enable(); 930 if (listeners > 0) { 931 p.setMinTime(getMinTimeLocked(provider), mTmpWorkSource); 932 p.enableLocationTracking(true); 933 } 934 } else { 935 p.enableLocationTracking(false); 936 p.disable(); 937 } 938 } 939 940 private long getMinTimeLocked(String provider) { 941 long minTime = Long.MAX_VALUE; 942 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 943 mTmpWorkSource.clear(); 944 if (records != null) { 945 for (int i=records.size()-1; i>=0; i--) { 946 UpdateRecord ur = records.get(i); 947 long curTime = ur.mMinTime; 948 if (curTime < minTime) { 949 minTime = curTime; 950 } 951 } 952 long inclTime = (minTime*3)/2; 953 for (int i=records.size()-1; i>=0; i--) { 954 UpdateRecord ur = records.get(i); 955 if (ur.mMinTime <= inclTime) { 956 mTmpWorkSource.add(ur.mUid); 957 } 958 } 959 } 960 return minTime; 961 } 962 963 private class UpdateRecord { 964 final String mProvider; 965 final Receiver mReceiver; 966 final long mMinTime; 967 final float mMinDistance; 968 final boolean mSingleShot; 969 final int mUid; 970 Location mLastFixBroadcast; 971 long mLastStatusBroadcast; 972 973 /** 974 * Note: must be constructed with lock held. 975 */ 976 UpdateRecord(String provider, long minTime, float minDistance, boolean singleShot, 977 Receiver receiver, int uid) { 978 mProvider = provider; 979 mReceiver = receiver; 980 mMinTime = minTime; 981 mMinDistance = minDistance; 982 mSingleShot = singleShot; 983 mUid = uid; 984 985 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 986 if (records == null) { 987 records = new ArrayList<UpdateRecord>(); 988 mRecordsByProvider.put(provider, records); 989 } 990 if (!records.contains(this)) { 991 records.add(this); 992 } 993 } 994 995 /** 996 * Method to be called when a record will no longer be used. Calling this multiple times 997 * must have the same effect as calling it once. 998 */ 999 void disposeLocked() { 1000 ArrayList<UpdateRecord> records = mRecordsByProvider.get(this.mProvider); 1001 if (records != null) { 1002 records.remove(this); 1003 } 1004 } 1005 1006 @Override 1007 public String toString() { 1008 return "UpdateRecord{" 1009 + Integer.toHexString(System.identityHashCode(this)) 1010 + " mProvider: " + mProvider + " mUid: " + mUid + "}"; 1011 } 1012 1013 void dump(PrintWriter pw, String prefix) { 1014 pw.println(prefix + this); 1015 pw.println(prefix + "mProvider=" + mProvider + " mReceiver=" + mReceiver); 1016 pw.println(prefix + "mMinTime=" + mMinTime + " mMinDistance=" + mMinDistance); 1017 pw.println(prefix + "mSingleShot=" + mSingleShot); 1018 pw.println(prefix + "mUid=" + mUid); 1019 pw.println(prefix + "mLastFixBroadcast:"); 1020 if (mLastFixBroadcast != null) { 1021 mLastFixBroadcast.dump(new PrintWriterPrinter(pw), prefix + " "); 1022 } 1023 pw.println(prefix + "mLastStatusBroadcast=" + mLastStatusBroadcast); 1024 } 1025 } 1026 1027 private Receiver getReceiver(ILocationListener listener) { 1028 IBinder binder = listener.asBinder(); 1029 Receiver receiver = mReceivers.get(binder); 1030 if (receiver == null) { 1031 receiver = new Receiver(listener); 1032 mReceivers.put(binder, receiver); 1033 1034 try { 1035 if (receiver.isListener()) { 1036 receiver.getListener().asBinder().linkToDeath(receiver, 0); 1037 } 1038 } catch (RemoteException e) { 1039 Slog.e(TAG, "linkToDeath failed:", e); 1040 return null; 1041 } 1042 } 1043 return receiver; 1044 } 1045 1046 private Receiver getReceiver(PendingIntent intent) { 1047 Receiver receiver = mReceivers.get(intent); 1048 if (receiver == null) { 1049 receiver = new Receiver(intent); 1050 mReceivers.put(intent, receiver); 1051 } 1052 return receiver; 1053 } 1054 1055 private boolean providerHasListener(String provider, int uid, Receiver excludedReceiver) { 1056 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 1057 if (records != null) { 1058 for (int i = records.size() - 1; i >= 0; i--) { 1059 UpdateRecord record = records.get(i); 1060 if (record.mUid == uid && record.mReceiver != excludedReceiver) { 1061 return true; 1062 } 1063 } 1064 } 1065 for (ProximityAlert alert : mProximityAlerts.values()) { 1066 if (alert.mUid == uid) { 1067 return true; 1068 } 1069 } 1070 return false; 1071 } 1072 1073 public void requestLocationUpdates(String provider, Criteria criteria, 1074 long minTime, float minDistance, boolean singleShot, ILocationListener listener) { 1075 if (criteria != null) { 1076 // FIXME - should we consider using multiple providers simultaneously 1077 // rather than only the best one? 1078 // Should we do anything different for single shot fixes? 1079 provider = getBestProvider(criteria, true); 1080 if (provider == null) { 1081 throw new IllegalArgumentException("no providers found for criteria"); 1082 } 1083 } 1084 try { 1085 synchronized (mLock) { 1086 requestLocationUpdatesLocked(provider, minTime, minDistance, singleShot, 1087 getReceiver(listener)); 1088 } 1089 } catch (SecurityException se) { 1090 throw se; 1091 } catch (IllegalArgumentException iae) { 1092 throw iae; 1093 } catch (Exception e) { 1094 Slog.e(TAG, "requestUpdates got exception:", e); 1095 } 1096 } 1097 1098 public void requestLocationUpdatesPI(String provider, Criteria criteria, 1099 long minTime, float minDistance, boolean singleShot, PendingIntent intent) { 1100 if (criteria != null) { 1101 // FIXME - should we consider using multiple providers simultaneously 1102 // rather than only the best one? 1103 // Should we do anything different for single shot fixes? 1104 provider = getBestProvider(criteria, true); 1105 if (provider == null) { 1106 throw new IllegalArgumentException("no providers found for criteria"); 1107 } 1108 } 1109 try { 1110 synchronized (mLock) { 1111 requestLocationUpdatesLocked(provider, minTime, minDistance, singleShot, 1112 getReceiver(intent)); 1113 } 1114 } catch (SecurityException se) { 1115 throw se; 1116 } catch (IllegalArgumentException iae) { 1117 throw iae; 1118 } catch (Exception e) { 1119 Slog.e(TAG, "requestUpdates got exception:", e); 1120 } 1121 } 1122 1123 private void requestLocationUpdatesLocked(String provider, long minTime, float minDistance, 1124 boolean singleShot, Receiver receiver) { 1125 1126 LocationProviderInterface p = mProvidersByName.get(provider); 1127 if (p == null) { 1128 throw new IllegalArgumentException("provider=" + provider); 1129 } 1130 1131 checkPermissionsSafe(provider); 1132 1133 // so wakelock calls will succeed 1134 final int callingUid = Binder.getCallingUid(); 1135 boolean newUid = !providerHasListener(provider, callingUid, null); 1136 long identity = Binder.clearCallingIdentity(); 1137 try { 1138 UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, singleShot, 1139 receiver, callingUid); 1140 UpdateRecord oldRecord = receiver.mUpdateRecords.put(provider, r); 1141 if (oldRecord != null) { 1142 oldRecord.disposeLocked(); 1143 } 1144 1145 if (newUid) { 1146 p.addListener(callingUid); 1147 } 1148 1149 boolean isProviderEnabled = isAllowedBySettingsLocked(provider); 1150 if (isProviderEnabled) { 1151 long minTimeForProvider = getMinTimeLocked(provider); 1152 p.setMinTime(minTimeForProvider, mTmpWorkSource); 1153 // try requesting single shot if singleShot is true, and fall back to 1154 // regular location tracking if requestSingleShotFix() is not supported 1155 if (!singleShot || !p.requestSingleShotFix()) { 1156 p.enableLocationTracking(true); 1157 } 1158 } else { 1159 // Notify the listener that updates are currently disabled 1160 receiver.callProviderEnabledLocked(provider, false); 1161 } 1162 if (LOCAL_LOGV) { 1163 Slog.v(TAG, "_requestLocationUpdates: provider = " + provider + " listener = " + receiver); 1164 } 1165 } finally { 1166 Binder.restoreCallingIdentity(identity); 1167 } 1168 } 1169 1170 public void removeUpdates(ILocationListener listener) { 1171 try { 1172 synchronized (mLock) { 1173 removeUpdatesLocked(getReceiver(listener)); 1174 } 1175 } catch (SecurityException se) { 1176 throw se; 1177 } catch (IllegalArgumentException iae) { 1178 throw iae; 1179 } catch (Exception e) { 1180 Slog.e(TAG, "removeUpdates got exception:", e); 1181 } 1182 } 1183 1184 public void removeUpdatesPI(PendingIntent intent) { 1185 try { 1186 synchronized (mLock) { 1187 removeUpdatesLocked(getReceiver(intent)); 1188 } 1189 } catch (SecurityException se) { 1190 throw se; 1191 } catch (IllegalArgumentException iae) { 1192 throw iae; 1193 } catch (Exception e) { 1194 Slog.e(TAG, "removeUpdates got exception:", e); 1195 } 1196 } 1197 1198 private void removeUpdatesLocked(Receiver receiver) { 1199 if (LOCAL_LOGV) { 1200 Slog.v(TAG, "_removeUpdates: listener = " + receiver); 1201 } 1202 1203 // so wakelock calls will succeed 1204 final int callingUid = Binder.getCallingUid(); 1205 long identity = Binder.clearCallingIdentity(); 1206 try { 1207 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) { 1208 receiver.getListener().asBinder().unlinkToDeath(receiver, 0); 1209 synchronized(receiver) { 1210 if(receiver.mPendingBroadcasts > 0) { 1211 decrementPendingBroadcasts(); 1212 receiver.mPendingBroadcasts = 0; 1213 } 1214 } 1215 } 1216 1217 // Record which providers were associated with this listener 1218 HashSet<String> providers = new HashSet<String>(); 1219 HashMap<String,UpdateRecord> oldRecords = receiver.mUpdateRecords; 1220 if (oldRecords != null) { 1221 // Call dispose() on the obsolete update records. 1222 for (UpdateRecord record : oldRecords.values()) { 1223 if (!providerHasListener(record.mProvider, callingUid, receiver)) { 1224 LocationProviderInterface p = mProvidersByName.get(record.mProvider); 1225 if (p != null) { 1226 p.removeListener(callingUid); 1227 } 1228 } 1229 record.disposeLocked(); 1230 } 1231 // Accumulate providers 1232 providers.addAll(oldRecords.keySet()); 1233 } 1234 1235 // See if the providers associated with this listener have any 1236 // other listeners; if one does, inform it of the new smallest minTime 1237 // value; if one does not, disable location tracking for it 1238 for (String provider : providers) { 1239 // If provider is already disabled, don't need to do anything 1240 if (!isAllowedBySettingsLocked(provider)) { 1241 continue; 1242 } 1243 1244 boolean hasOtherListener = false; 1245 ArrayList<UpdateRecord> recordsForProvider = mRecordsByProvider.get(provider); 1246 if (recordsForProvider != null && recordsForProvider.size() > 0) { 1247 hasOtherListener = true; 1248 } 1249 1250 LocationProviderInterface p = mProvidersByName.get(provider); 1251 if (p != null) { 1252 if (hasOtherListener) { 1253 p.setMinTime(getMinTimeLocked(provider), mTmpWorkSource); 1254 } else { 1255 p.enableLocationTracking(false); 1256 } 1257 } 1258 } 1259 } finally { 1260 Binder.restoreCallingIdentity(identity); 1261 } 1262 } 1263 1264 public boolean addGpsStatusListener(IGpsStatusListener listener) { 1265 if (mGpsStatusProvider == null) { 1266 return false; 1267 } 1268 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) != 1269 PackageManager.PERMISSION_GRANTED) { 1270 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); 1271 } 1272 1273 try { 1274 mGpsStatusProvider.addGpsStatusListener(listener); 1275 } catch (RemoteException e) { 1276 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e); 1277 return false; 1278 } 1279 return true; 1280 } 1281 1282 public void removeGpsStatusListener(IGpsStatusListener listener) { 1283 synchronized (mLock) { 1284 try { 1285 mGpsStatusProvider.removeGpsStatusListener(listener); 1286 } catch (Exception e) { 1287 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e); 1288 } 1289 } 1290 } 1291 1292 public boolean sendExtraCommand(String provider, String command, Bundle extras) { 1293 if (provider == null) { 1294 // throw NullPointerException to remain compatible with previous implementation 1295 throw new NullPointerException(); 1296 } 1297 1298 // first check for permission to the provider 1299 checkPermissionsSafe(provider); 1300 // and check for ACCESS_LOCATION_EXTRA_COMMANDS 1301 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS) 1302 != PackageManager.PERMISSION_GRANTED)) { 1303 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission"); 1304 } 1305 1306 synchronized (mLock) { 1307 LocationProviderInterface p = mProvidersByName.get(provider); 1308 if (p == null) { 1309 return false; 1310 } 1311 1312 return p.sendExtraCommand(command, extras); 1313 } 1314 } 1315 1316 public boolean sendNiResponse(int notifId, int userResponse) 1317 { 1318 if (Binder.getCallingUid() != Process.myUid()) { 1319 throw new SecurityException( 1320 "calling sendNiResponse from outside of the system is not allowed"); 1321 } 1322 try { 1323 return mNetInitiatedListener.sendNiResponse(notifId, userResponse); 1324 } 1325 catch (RemoteException e) 1326 { 1327 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse"); 1328 return false; 1329 } 1330 } 1331 1332 class ProximityAlert { 1333 final int mUid; 1334 final double mLatitude; 1335 final double mLongitude; 1336 final float mRadius; 1337 final long mExpiration; 1338 final PendingIntent mIntent; 1339 final Location mLocation; 1340 1341 public ProximityAlert(int uid, double latitude, double longitude, 1342 float radius, long expiration, PendingIntent intent) { 1343 mUid = uid; 1344 mLatitude = latitude; 1345 mLongitude = longitude; 1346 mRadius = radius; 1347 mExpiration = expiration; 1348 mIntent = intent; 1349 1350 mLocation = new Location(""); 1351 mLocation.setLatitude(latitude); 1352 mLocation.setLongitude(longitude); 1353 } 1354 1355 long getExpiration() { 1356 return mExpiration; 1357 } 1358 1359 PendingIntent getIntent() { 1360 return mIntent; 1361 } 1362 1363 boolean isInProximity(double latitude, double longitude, float accuracy) { 1364 Location loc = new Location(""); 1365 loc.setLatitude(latitude); 1366 loc.setLongitude(longitude); 1367 1368 double radius = loc.distanceTo(mLocation); 1369 return radius <= Math.max(mRadius,accuracy); 1370 } 1371 1372 @Override 1373 public String toString() { 1374 return "ProximityAlert{" 1375 + Integer.toHexString(System.identityHashCode(this)) 1376 + " uid " + mUid + mIntent + "}"; 1377 } 1378 1379 void dump(PrintWriter pw, String prefix) { 1380 pw.println(prefix + this); 1381 pw.println(prefix + "mLatitude=" + mLatitude + " mLongitude=" + mLongitude); 1382 pw.println(prefix + "mRadius=" + mRadius + " mExpiration=" + mExpiration); 1383 pw.println(prefix + "mIntent=" + mIntent); 1384 pw.println(prefix + "mLocation:"); 1385 mLocation.dump(new PrintWriterPrinter(pw), prefix + " "); 1386 } 1387 } 1388 1389 // Listener for receiving locations to trigger proximity alerts 1390 class ProximityListener extends ILocationListener.Stub implements PendingIntent.OnFinished { 1391 1392 boolean isGpsAvailable = false; 1393 1394 // Note: this is called with the lock held. 1395 public void onLocationChanged(Location loc) { 1396 1397 // If Gps is available, then ignore updates from NetworkLocationProvider 1398 if (loc.getProvider().equals(LocationManager.GPS_PROVIDER)) { 1399 isGpsAvailable = true; 1400 } 1401 if (isGpsAvailable && loc.getProvider().equals(LocationManager.NETWORK_PROVIDER)) { 1402 return; 1403 } 1404 1405 // Process proximity alerts 1406 long now = System.currentTimeMillis(); 1407 double latitude = loc.getLatitude(); 1408 double longitude = loc.getLongitude(); 1409 float accuracy = loc.getAccuracy(); 1410 ArrayList<PendingIntent> intentsToRemove = null; 1411 1412 for (ProximityAlert alert : mProximityAlerts.values()) { 1413 PendingIntent intent = alert.getIntent(); 1414 long expiration = alert.getExpiration(); 1415 1416 if ((expiration == -1) || (now <= expiration)) { 1417 boolean entered = mProximitiesEntered.contains(alert); 1418 boolean inProximity = 1419 alert.isInProximity(latitude, longitude, accuracy); 1420 if (!entered && inProximity) { 1421 if (LOCAL_LOGV) { 1422 Slog.v(TAG, "Entered alert"); 1423 } 1424 mProximitiesEntered.add(alert); 1425 Intent enteredIntent = new Intent(); 1426 enteredIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true); 1427 try { 1428 synchronized (this) { 1429 // synchronize to ensure incrementPendingBroadcasts() 1430 // is called before decrementPendingBroadcasts() 1431 intent.send(mContext, 0, enteredIntent, this, mLocationHandler); 1432 // call this after broadcasting so we do not increment 1433 // if we throw an exeption. 1434 incrementPendingBroadcasts(); 1435 } 1436 } catch (PendingIntent.CanceledException e) { 1437 if (LOCAL_LOGV) { 1438 Slog.v(TAG, "Canceled proximity alert: " + alert, e); 1439 } 1440 if (intentsToRemove == null) { 1441 intentsToRemove = new ArrayList<PendingIntent>(); 1442 } 1443 intentsToRemove.add(intent); 1444 } 1445 } else if (entered && !inProximity) { 1446 if (LOCAL_LOGV) { 1447 Slog.v(TAG, "Exited alert"); 1448 } 1449 mProximitiesEntered.remove(alert); 1450 Intent exitedIntent = new Intent(); 1451 exitedIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false); 1452 try { 1453 synchronized (this) { 1454 // synchronize to ensure incrementPendingBroadcasts() 1455 // is called before decrementPendingBroadcasts() 1456 intent.send(mContext, 0, exitedIntent, this, mLocationHandler); 1457 // call this after broadcasting so we do not increment 1458 // if we throw an exeption. 1459 incrementPendingBroadcasts(); 1460 } 1461 } catch (PendingIntent.CanceledException e) { 1462 if (LOCAL_LOGV) { 1463 Slog.v(TAG, "Canceled proximity alert: " + alert, e); 1464 } 1465 if (intentsToRemove == null) { 1466 intentsToRemove = new ArrayList<PendingIntent>(); 1467 } 1468 intentsToRemove.add(intent); 1469 } 1470 } 1471 } else { 1472 // Mark alert for expiration 1473 if (LOCAL_LOGV) { 1474 Slog.v(TAG, "Expiring proximity alert: " + alert); 1475 } 1476 if (intentsToRemove == null) { 1477 intentsToRemove = new ArrayList<PendingIntent>(); 1478 } 1479 intentsToRemove.add(alert.getIntent()); 1480 } 1481 } 1482 1483 // Remove expired alerts 1484 if (intentsToRemove != null) { 1485 for (PendingIntent i : intentsToRemove) { 1486 ProximityAlert alert = mProximityAlerts.get(i); 1487 mProximitiesEntered.remove(alert); 1488 removeProximityAlertLocked(i); 1489 } 1490 } 1491 } 1492 1493 // Note: this is called with the lock held. 1494 public void onProviderDisabled(String provider) { 1495 if (provider.equals(LocationManager.GPS_PROVIDER)) { 1496 isGpsAvailable = false; 1497 } 1498 } 1499 1500 // Note: this is called with the lock held. 1501 public void onProviderEnabled(String provider) { 1502 // ignore 1503 } 1504 1505 // Note: this is called with the lock held. 1506 public void onStatusChanged(String provider, int status, Bundle extras) { 1507 if ((provider.equals(LocationManager.GPS_PROVIDER)) && 1508 (status != LocationProvider.AVAILABLE)) { 1509 isGpsAvailable = false; 1510 } 1511 } 1512 1513 public void onSendFinished(PendingIntent pendingIntent, Intent intent, 1514 int resultCode, String resultData, Bundle resultExtras) { 1515 // synchronize to ensure incrementPendingBroadcasts() 1516 // is called before decrementPendingBroadcasts() 1517 synchronized (this) { 1518 decrementPendingBroadcasts(); 1519 } 1520 } 1521 } 1522 1523 public void addProximityAlert(double latitude, double longitude, 1524 float radius, long expiration, PendingIntent intent) { 1525 try { 1526 synchronized (mLock) { 1527 addProximityAlertLocked(latitude, longitude, radius, expiration, intent); 1528 } 1529 } catch (SecurityException se) { 1530 throw se; 1531 } catch (IllegalArgumentException iae) { 1532 throw iae; 1533 } catch (Exception e) { 1534 Slog.e(TAG, "addProximityAlert got exception:", e); 1535 } 1536 } 1537 1538 private void addProximityAlertLocked(double latitude, double longitude, 1539 float radius, long expiration, PendingIntent intent) { 1540 if (LOCAL_LOGV) { 1541 Slog.v(TAG, "addProximityAlert: latitude = " + latitude + 1542 ", longitude = " + longitude + 1543 ", expiration = " + expiration + 1544 ", intent = " + intent); 1545 } 1546 1547 // Require ability to access all providers for now 1548 if (!isAllowedProviderSafe(LocationManager.GPS_PROVIDER) || 1549 !isAllowedProviderSafe(LocationManager.NETWORK_PROVIDER)) { 1550 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); 1551 } 1552 1553 if (expiration != -1) { 1554 expiration += System.currentTimeMillis(); 1555 } 1556 ProximityAlert alert = new ProximityAlert(Binder.getCallingUid(), 1557 latitude, longitude, radius, expiration, intent); 1558 mProximityAlerts.put(intent, alert); 1559 1560 if (mProximityReceiver == null) { 1561 mProximityListener = new ProximityListener(); 1562 mProximityReceiver = new Receiver(mProximityListener); 1563 1564 for (int i = mProviders.size() - 1; i >= 0; i--) { 1565 LocationProviderInterface provider = mProviders.get(i); 1566 requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, 1567 false, mProximityReceiver); 1568 } 1569 } 1570 } 1571 1572 public void removeProximityAlert(PendingIntent intent) { 1573 try { 1574 synchronized (mLock) { 1575 removeProximityAlertLocked(intent); 1576 } 1577 } catch (SecurityException se) { 1578 throw se; 1579 } catch (IllegalArgumentException iae) { 1580 throw iae; 1581 } catch (Exception e) { 1582 Slog.e(TAG, "removeProximityAlert got exception:", e); 1583 } 1584 } 1585 1586 private void removeProximityAlertLocked(PendingIntent intent) { 1587 if (LOCAL_LOGV) { 1588 Slog.v(TAG, "removeProximityAlert: intent = " + intent); 1589 } 1590 1591 mProximityAlerts.remove(intent); 1592 if (mProximityAlerts.size() == 0) { 1593 removeUpdatesLocked(mProximityReceiver); 1594 mProximityReceiver = null; 1595 mProximityListener = null; 1596 } 1597 } 1598 1599 /** 1600 * @return null if the provider does not exist 1601 * @throws SecurityException if the provider is not allowed to be 1602 * accessed by the caller 1603 */ 1604 public Bundle getProviderInfo(String provider) { 1605 try { 1606 synchronized (mLock) { 1607 return _getProviderInfoLocked(provider); 1608 } 1609 } catch (SecurityException se) { 1610 throw se; 1611 } catch (IllegalArgumentException iae) { 1612 throw iae; 1613 } catch (Exception e) { 1614 Slog.e(TAG, "_getProviderInfo got exception:", e); 1615 return null; 1616 } 1617 } 1618 1619 private Bundle _getProviderInfoLocked(String provider) { 1620 LocationProviderInterface p = mProvidersByName.get(provider); 1621 if (p == null) { 1622 return null; 1623 } 1624 1625 checkPermissionsSafe(provider); 1626 1627 Bundle b = new Bundle(); 1628 b.putBoolean("network", p.requiresNetwork()); 1629 b.putBoolean("satellite", p.requiresSatellite()); 1630 b.putBoolean("cell", p.requiresCell()); 1631 b.putBoolean("cost", p.hasMonetaryCost()); 1632 b.putBoolean("altitude", p.supportsAltitude()); 1633 b.putBoolean("speed", p.supportsSpeed()); 1634 b.putBoolean("bearing", p.supportsBearing()); 1635 b.putInt("power", p.getPowerRequirement()); 1636 b.putInt("accuracy", p.getAccuracy()); 1637 1638 return b; 1639 } 1640 1641 public boolean isProviderEnabled(String provider) { 1642 try { 1643 synchronized (mLock) { 1644 return _isProviderEnabledLocked(provider); 1645 } 1646 } catch (SecurityException se) { 1647 throw se; 1648 } catch (Exception e) { 1649 Slog.e(TAG, "isProviderEnabled got exception:", e); 1650 return false; 1651 } 1652 } 1653 1654 public void reportLocation(Location location, boolean passive) { 1655 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER) 1656 != PackageManager.PERMISSION_GRANTED) { 1657 throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission"); 1658 } 1659 1660 mLocationHandler.removeMessages(MESSAGE_LOCATION_CHANGED, location); 1661 Message m = Message.obtain(mLocationHandler, MESSAGE_LOCATION_CHANGED, location); 1662 m.arg1 = (passive ? 1 : 0); 1663 mLocationHandler.sendMessageAtFrontOfQueue(m); 1664 } 1665 1666 private boolean _isProviderEnabledLocked(String provider) { 1667 checkPermissionsSafe(provider); 1668 1669 LocationProviderInterface p = mProvidersByName.get(provider); 1670 if (p == null) { 1671 return false; 1672 } 1673 return isAllowedBySettingsLocked(provider); 1674 } 1675 1676 public Location getLastKnownLocation(String provider) { 1677 try { 1678 synchronized (mLock) { 1679 return _getLastKnownLocationLocked(provider); 1680 } 1681 } catch (SecurityException se) { 1682 throw se; 1683 } catch (Exception e) { 1684 Slog.e(TAG, "getLastKnownLocation got exception:", e); 1685 return null; 1686 } 1687 } 1688 1689 private Location _getLastKnownLocationLocked(String provider) { 1690 checkPermissionsSafe(provider); 1691 1692 LocationProviderInterface p = mProvidersByName.get(provider); 1693 if (p == null) { 1694 return null; 1695 } 1696 1697 if (!isAllowedBySettingsLocked(provider)) { 1698 return null; 1699 } 1700 1701 return mLastKnownLocation.get(provider); 1702 } 1703 1704 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) { 1705 // Always broadcast the first update 1706 if (lastLoc == null) { 1707 return true; 1708 } 1709 1710 // Don't broadcast same location again regardless of condition 1711 // TODO - we should probably still rebroadcast if user explicitly sets a minTime > 0 1712 if (loc.getTime() == lastLoc.getTime()) { 1713 return false; 1714 } 1715 1716 // Check whether sufficient distance has been traveled 1717 double minDistance = record.mMinDistance; 1718 if (minDistance > 0.0) { 1719 if (loc.distanceTo(lastLoc) <= minDistance) { 1720 return false; 1721 } 1722 } 1723 1724 return true; 1725 } 1726 1727 private void handleLocationChangedLocked(Location location, boolean passive) { 1728 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider()); 1729 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 1730 if (records == null || records.size() == 0) { 1731 return; 1732 } 1733 1734 LocationProviderInterface p = mProvidersByName.get(provider); 1735 if (p == null) { 1736 return; 1737 } 1738 1739 // Update last known location for provider 1740 Location lastLocation = mLastKnownLocation.get(provider); 1741 if (lastLocation == null) { 1742 mLastKnownLocation.put(provider, new Location(location)); 1743 } else { 1744 lastLocation.set(location); 1745 } 1746 1747 // Fetch latest status update time 1748 long newStatusUpdateTime = p.getStatusUpdateTime(); 1749 1750 // Get latest status 1751 Bundle extras = new Bundle(); 1752 int status = p.getStatus(extras); 1753 1754 ArrayList<Receiver> deadReceivers = null; 1755 1756 // Broadcast location or status to all listeners 1757 final int N = records.size(); 1758 for (int i=0; i<N; i++) { 1759 UpdateRecord r = records.get(i); 1760 Receiver receiver = r.mReceiver; 1761 boolean receiverDead = false; 1762 1763 Location lastLoc = r.mLastFixBroadcast; 1764 if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) { 1765 if (lastLoc == null) { 1766 lastLoc = new Location(location); 1767 r.mLastFixBroadcast = lastLoc; 1768 } else { 1769 lastLoc.set(location); 1770 } 1771 if (!receiver.callLocationChangedLocked(location)) { 1772 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver); 1773 receiverDead = true; 1774 } 1775 } 1776 1777 long prevStatusUpdateTime = r.mLastStatusBroadcast; 1778 if ((newStatusUpdateTime > prevStatusUpdateTime) && 1779 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) { 1780 1781 r.mLastStatusBroadcast = newStatusUpdateTime; 1782 if (!receiver.callStatusChangedLocked(provider, status, extras)) { 1783 receiverDead = true; 1784 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver); 1785 } 1786 } 1787 1788 // remove receiver if it is dead or we just processed a single shot request 1789 if (receiverDead || r.mSingleShot) { 1790 if (deadReceivers == null) { 1791 deadReceivers = new ArrayList<Receiver>(); 1792 } 1793 if (!deadReceivers.contains(receiver)) { 1794 deadReceivers.add(receiver); 1795 } 1796 } 1797 } 1798 1799 if (deadReceivers != null) { 1800 for (int i=deadReceivers.size()-1; i>=0; i--) { 1801 removeUpdatesLocked(deadReceivers.get(i)); 1802 } 1803 } 1804 } 1805 1806 private class LocationWorkerHandler extends Handler { 1807 1808 @Override 1809 public void handleMessage(Message msg) { 1810 try { 1811 if (msg.what == MESSAGE_LOCATION_CHANGED) { 1812 // log("LocationWorkerHandler: MESSAGE_LOCATION_CHANGED!"); 1813 1814 synchronized (mLock) { 1815 Location location = (Location) msg.obj; 1816 String provider = location.getProvider(); 1817 boolean passive = (msg.arg1 == 1); 1818 1819 if (!passive) { 1820 // notify other providers of the new location 1821 for (int i = mProviders.size() - 1; i >= 0; i--) { 1822 LocationProviderInterface p = mProviders.get(i); 1823 if (!provider.equals(p.getName())) { 1824 p.updateLocation(location); 1825 } 1826 } 1827 } 1828 1829 if (isAllowedBySettingsLocked(provider)) { 1830 handleLocationChangedLocked(location, passive); 1831 } 1832 } 1833 } else if (msg.what == MESSAGE_PACKAGE_UPDATED) { 1834 String packageName = (String) msg.obj; 1835 String packageDot = packageName + "."; 1836 1837 // reconnect to external providers after their packages have been updated 1838 if (mNetworkLocationProvider != null && 1839 mNetworkLocationProviderPackageName.startsWith(packageDot)) { 1840 mNetworkLocationProvider.reconnect(); 1841 } 1842 if (mGeocodeProvider != null && 1843 mGeocodeProviderPackageName.startsWith(packageDot)) { 1844 mGeocodeProvider.reconnect(); 1845 } 1846 } 1847 } catch (Exception e) { 1848 // Log, don't crash! 1849 Slog.e(TAG, "Exception in LocationWorkerHandler.handleMessage:", e); 1850 } 1851 } 1852 } 1853 1854 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 1855 @Override 1856 public void onReceive(Context context, Intent intent) { 1857 String action = intent.getAction(); 1858 boolean queryRestart = action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART); 1859 if (queryRestart 1860 || action.equals(Intent.ACTION_PACKAGE_REMOVED) 1861 || action.equals(Intent.ACTION_PACKAGE_RESTARTED) 1862 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { 1863 synchronized (mLock) { 1864 int uidList[] = null; 1865 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { 1866 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 1867 } else { 1868 uidList = new int[]{intent.getIntExtra(Intent.EXTRA_UID, -1)}; 1869 } 1870 if (uidList == null || uidList.length == 0) { 1871 return; 1872 } 1873 for (int uid : uidList) { 1874 if (uid >= 0) { 1875 ArrayList<Receiver> removedRecs = null; 1876 for (ArrayList<UpdateRecord> i : mRecordsByProvider.values()) { 1877 for (int j=i.size()-1; j>=0; j--) { 1878 UpdateRecord ur = i.get(j); 1879 if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) { 1880 if (queryRestart) { 1881 setResultCode(Activity.RESULT_OK); 1882 return; 1883 } 1884 if (removedRecs == null) { 1885 removedRecs = new ArrayList<Receiver>(); 1886 } 1887 if (!removedRecs.contains(ur.mReceiver)) { 1888 removedRecs.add(ur.mReceiver); 1889 } 1890 } 1891 } 1892 } 1893 ArrayList<ProximityAlert> removedAlerts = null; 1894 for (ProximityAlert i : mProximityAlerts.values()) { 1895 if (i.mUid == uid) { 1896 if (queryRestart) { 1897 setResultCode(Activity.RESULT_OK); 1898 return; 1899 } 1900 if (removedAlerts == null) { 1901 removedAlerts = new ArrayList<ProximityAlert>(); 1902 } 1903 if (!removedAlerts.contains(i)) { 1904 removedAlerts.add(i); 1905 } 1906 } 1907 } 1908 if (removedRecs != null) { 1909 for (int i=removedRecs.size()-1; i>=0; i--) { 1910 removeUpdatesLocked(removedRecs.get(i)); 1911 } 1912 } 1913 if (removedAlerts != null) { 1914 for (int i=removedAlerts.size()-1; i>=0; i--) { 1915 removeProximityAlertLocked(removedAlerts.get(i).mIntent); 1916 } 1917 } 1918 } 1919 } 1920 } 1921 } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 1922 boolean noConnectivity = 1923 intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); 1924 if (!noConnectivity) { 1925 mNetworkState = LocationProvider.AVAILABLE; 1926 } else { 1927 mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE; 1928 } 1929 NetworkInfo info = 1930 (NetworkInfo)intent.getExtra(ConnectivityManager.EXTRA_NETWORK_INFO); 1931 1932 // Notify location providers of current network state 1933 synchronized (mLock) { 1934 for (int i = mProviders.size() - 1; i >= 0; i--) { 1935 LocationProviderInterface provider = mProviders.get(i); 1936 if (provider.requiresNetwork()) { 1937 provider.updateNetworkState(mNetworkState, info); 1938 } 1939 } 1940 } 1941 } 1942 } 1943 }; 1944 1945 private final PackageMonitor mPackageMonitor = new PackageMonitor() { 1946 @Override 1947 public void onPackageUpdateFinished(String packageName, int uid) { 1948 // Called by main thread; divert work to LocationWorker. 1949 Message.obtain(mLocationHandler, MESSAGE_PACKAGE_UPDATED, packageName).sendToTarget(); 1950 } 1951 }; 1952 1953 // Wake locks 1954 1955 private void incrementPendingBroadcasts() { 1956 synchronized (mWakeLock) { 1957 if (mPendingBroadcasts++ == 0) { 1958 try { 1959 mWakeLock.acquire(); 1960 log("Acquired wakelock"); 1961 } catch (Exception e) { 1962 // This is to catch a runtime exception thrown when we try to release an 1963 // already released lock. 1964 Slog.e(TAG, "exception in acquireWakeLock()", e); 1965 } 1966 } 1967 } 1968 } 1969 1970 private void decrementPendingBroadcasts() { 1971 synchronized (mWakeLock) { 1972 if (--mPendingBroadcasts == 0) { 1973 try { 1974 // Release wake lock 1975 if (mWakeLock.isHeld()) { 1976 mWakeLock.release(); 1977 log("Released wakelock"); 1978 } else { 1979 log("Can't release wakelock again!"); 1980 } 1981 } catch (Exception e) { 1982 // This is to catch a runtime exception thrown when we try to release an 1983 // already released lock. 1984 Slog.e(TAG, "exception in releaseWakeLock()", e); 1985 } 1986 } 1987 } 1988 } 1989 1990 // Geocoder 1991 1992 public boolean geocoderIsPresent() { 1993 return mGeocodeProvider != null; 1994 } 1995 1996 public String getFromLocation(double latitude, double longitude, int maxResults, 1997 GeocoderParams params, List<Address> addrs) { 1998 if (mGeocodeProvider != null) { 1999 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, 2000 params, addrs); 2001 } 2002 return null; 2003 } 2004 2005 2006 public String getFromLocationName(String locationName, 2007 double lowerLeftLatitude, double lowerLeftLongitude, 2008 double upperRightLatitude, double upperRightLongitude, int maxResults, 2009 GeocoderParams params, List<Address> addrs) { 2010 2011 if (mGeocodeProvider != null) { 2012 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude, 2013 lowerLeftLongitude, upperRightLatitude, upperRightLongitude, 2014 maxResults, params, addrs); 2015 } 2016 return null; 2017 } 2018 2019 // Mock Providers 2020 2021 private void checkMockPermissionsSafe() { 2022 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(), 2023 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1; 2024 if (!allowMocks) { 2025 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting"); 2026 } 2027 2028 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) != 2029 PackageManager.PERMISSION_GRANTED) { 2030 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission"); 2031 } 2032 } 2033 2034 public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite, 2035 boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, 2036 boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) { 2037 checkMockPermissionsSafe(); 2038 2039 if (LocationManager.PASSIVE_PROVIDER.equals(name)) { 2040 throw new IllegalArgumentException("Cannot mock the passive location provider"); 2041 } 2042 2043 long identity = Binder.clearCallingIdentity(); 2044 synchronized (mLock) { 2045 MockProvider provider = new MockProvider(name, this, 2046 requiresNetwork, requiresSatellite, 2047 requiresCell, hasMonetaryCost, supportsAltitude, 2048 supportsSpeed, supportsBearing, powerRequirement, accuracy); 2049 // remove the real provider if we are replacing GPS or network provider 2050 if (LocationManager.GPS_PROVIDER.equals(name) 2051 || LocationManager.NETWORK_PROVIDER.equals(name)) { 2052 LocationProviderInterface p = mProvidersByName.get(name); 2053 if (p != null) { 2054 p.enableLocationTracking(false); 2055 removeProvider(p); 2056 } 2057 } 2058 if (mProvidersByName.get(name) != null) { 2059 throw new IllegalArgumentException("Provider \"" + name + "\" already exists"); 2060 } 2061 addProvider(provider); 2062 mMockProviders.put(name, provider); 2063 mLastKnownLocation.put(name, null); 2064 updateProvidersLocked(); 2065 } 2066 Binder.restoreCallingIdentity(identity); 2067 } 2068 2069 public void removeTestProvider(String provider) { 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 removeProvider(mProvidersByName.get(provider)); 2078 mMockProviders.remove(mockProvider); 2079 // reinstall real provider if we were mocking GPS or network provider 2080 if (LocationManager.GPS_PROVIDER.equals(provider) && 2081 mGpsLocationProvider != null) { 2082 addProvider(mGpsLocationProvider); 2083 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) && 2084 mNetworkLocationProvider != null) { 2085 addProvider(mNetworkLocationProvider); 2086 } 2087 mLastKnownLocation.put(provider, null); 2088 updateProvidersLocked(); 2089 Binder.restoreCallingIdentity(identity); 2090 } 2091 } 2092 2093 public void setTestProviderLocation(String provider, Location loc) { 2094 checkMockPermissionsSafe(); 2095 synchronized (mLock) { 2096 MockProvider mockProvider = mMockProviders.get(provider); 2097 if (mockProvider == null) { 2098 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2099 } 2100 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required 2101 long identity = Binder.clearCallingIdentity(); 2102 mockProvider.setLocation(loc); 2103 Binder.restoreCallingIdentity(identity); 2104 } 2105 } 2106 2107 public void clearTestProviderLocation(String provider) { 2108 checkMockPermissionsSafe(); 2109 synchronized (mLock) { 2110 MockProvider mockProvider = mMockProviders.get(provider); 2111 if (mockProvider == null) { 2112 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2113 } 2114 mockProvider.clearLocation(); 2115 } 2116 } 2117 2118 public void setTestProviderEnabled(String provider, boolean enabled) { 2119 checkMockPermissionsSafe(); 2120 synchronized (mLock) { 2121 MockProvider mockProvider = mMockProviders.get(provider); 2122 if (mockProvider == null) { 2123 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2124 } 2125 long identity = Binder.clearCallingIdentity(); 2126 if (enabled) { 2127 mockProvider.enable(); 2128 mEnabledProviders.add(provider); 2129 mDisabledProviders.remove(provider); 2130 } else { 2131 mockProvider.disable(); 2132 mEnabledProviders.remove(provider); 2133 mDisabledProviders.add(provider); 2134 } 2135 updateProvidersLocked(); 2136 Binder.restoreCallingIdentity(identity); 2137 } 2138 } 2139 2140 public void clearTestProviderEnabled(String provider) { 2141 checkMockPermissionsSafe(); 2142 synchronized (mLock) { 2143 MockProvider mockProvider = mMockProviders.get(provider); 2144 if (mockProvider == null) { 2145 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2146 } 2147 long identity = Binder.clearCallingIdentity(); 2148 mEnabledProviders.remove(provider); 2149 mDisabledProviders.remove(provider); 2150 updateProvidersLocked(); 2151 Binder.restoreCallingIdentity(identity); 2152 } 2153 } 2154 2155 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) { 2156 checkMockPermissionsSafe(); 2157 synchronized (mLock) { 2158 MockProvider mockProvider = mMockProviders.get(provider); 2159 if (mockProvider == null) { 2160 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2161 } 2162 mockProvider.setStatus(status, extras, updateTime); 2163 } 2164 } 2165 2166 public void clearTestProviderStatus(String provider) { 2167 checkMockPermissionsSafe(); 2168 synchronized (mLock) { 2169 MockProvider mockProvider = mMockProviders.get(provider); 2170 if (mockProvider == null) { 2171 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2172 } 2173 mockProvider.clearStatus(); 2174 } 2175 } 2176 2177 private void log(String log) { 2178 if (Log.isLoggable(TAG, Log.VERBOSE)) { 2179 Slog.d(TAG, log); 2180 } 2181 } 2182 2183 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2184 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 2185 != PackageManager.PERMISSION_GRANTED) { 2186 pw.println("Permission Denial: can't dump LocationManagerService from from pid=" 2187 + Binder.getCallingPid() 2188 + ", uid=" + Binder.getCallingUid()); 2189 return; 2190 } 2191 2192 synchronized (mLock) { 2193 pw.println("Current Location Manager state:"); 2194 pw.println(" sProvidersLoaded=" + sProvidersLoaded); 2195 pw.println(" Listeners:"); 2196 int N = mReceivers.size(); 2197 for (int i=0; i<N; i++) { 2198 pw.println(" " + mReceivers.get(i)); 2199 } 2200 pw.println(" Location Listeners:"); 2201 for (Receiver i : mReceivers.values()) { 2202 pw.println(" " + i + ":"); 2203 for (Map.Entry<String,UpdateRecord> j : i.mUpdateRecords.entrySet()) { 2204 pw.println(" " + j.getKey() + ":"); 2205 j.getValue().dump(pw, " "); 2206 } 2207 } 2208 pw.println(" Records by Provider:"); 2209 for (Map.Entry<String, ArrayList<UpdateRecord>> i 2210 : mRecordsByProvider.entrySet()) { 2211 pw.println(" " + i.getKey() + ":"); 2212 for (UpdateRecord j : i.getValue()) { 2213 pw.println(" " + j + ":"); 2214 j.dump(pw, " "); 2215 } 2216 } 2217 pw.println(" Last Known Locations:"); 2218 for (Map.Entry<String, Location> i 2219 : mLastKnownLocation.entrySet()) { 2220 pw.println(" " + i.getKey() + ":"); 2221 i.getValue().dump(new PrintWriterPrinter(pw), " "); 2222 } 2223 if (mProximityAlerts.size() > 0) { 2224 pw.println(" Proximity Alerts:"); 2225 for (Map.Entry<PendingIntent, ProximityAlert> i 2226 : mProximityAlerts.entrySet()) { 2227 pw.println(" " + i.getKey() + ":"); 2228 i.getValue().dump(pw, " "); 2229 } 2230 } 2231 if (mProximitiesEntered.size() > 0) { 2232 pw.println(" Proximities Entered:"); 2233 for (ProximityAlert i : mProximitiesEntered) { 2234 pw.println(" " + i + ":"); 2235 i.dump(pw, " "); 2236 } 2237 } 2238 pw.println(" mProximityReceiver=" + mProximityReceiver); 2239 pw.println(" mProximityListener=" + mProximityListener); 2240 if (mEnabledProviders.size() > 0) { 2241 pw.println(" Enabled Providers:"); 2242 for (String i : mEnabledProviders) { 2243 pw.println(" " + i); 2244 } 2245 2246 } 2247 if (mDisabledProviders.size() > 0) { 2248 pw.println(" Disabled Providers:"); 2249 for (String i : mDisabledProviders) { 2250 pw.println(" " + i); 2251 } 2252 2253 } 2254 if (mMockProviders.size() > 0) { 2255 pw.println(" Mock Providers:"); 2256 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) { 2257 i.getValue().dump(pw, " "); 2258 } 2259 } 2260 for (LocationProviderInterface provider: mProviders) { 2261 String state = provider.getInternalState(); 2262 if (state != null) { 2263 pw.println(provider.getName() + " Internal State:"); 2264 pw.write(state); 2265 } 2266 } 2267 } 2268 } 2269} 2270