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