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