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