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