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