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