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