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