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.PackageInfo; 30import android.content.pm.PackageManager; 31import android.content.pm.ResolveInfo; 32import android.content.pm.PackageManager.NameNotFoundException; 33import android.content.pm.Signature; 34import android.content.res.Resources; 35import android.database.Cursor; 36import android.location.Address; 37import android.location.Criteria; 38import android.location.GeocoderParams; 39import android.location.IGpsStatusListener; 40import android.location.IGpsStatusProvider; 41import android.location.ILocationListener; 42import android.location.ILocationManager; 43import android.location.INetInitiatedListener; 44import android.location.Location; 45import android.location.LocationManager; 46import android.location.LocationProvider; 47import android.net.ConnectivityManager; 48import android.net.NetworkInfo; 49import android.net.Uri; 50import android.os.Binder; 51import android.os.Bundle; 52import android.os.Handler; 53import android.os.IBinder; 54import android.os.Looper; 55import android.os.Message; 56import android.os.PowerManager; 57import android.os.Process; 58import android.os.RemoteException; 59import android.os.WorkSource; 60import android.provider.Settings; 61import android.util.Log; 62import android.util.Slog; 63import android.util.PrintWriterPrinter; 64 65import com.android.internal.content.PackageMonitor; 66import com.android.internal.location.GpsNetInitiatedHandler; 67 68import com.android.server.location.GeocoderProxy; 69import com.android.server.location.GpsLocationProvider; 70import com.android.server.location.LocationProviderInterface; 71import com.android.server.location.LocationProviderProxy; 72import com.android.server.location.MockProvider; 73import com.android.server.location.PassiveProvider; 74 75import java.io.FileDescriptor; 76import java.io.PrintWriter; 77import java.util.ArrayList; 78import java.util.Collections; 79import java.util.Comparator; 80import java.util.HashMap; 81import java.util.HashSet; 82import java.util.List; 83import java.util.Map; 84import java.util.Observable; 85import java.util.Observer; 86import java.util.Set; 87 88/** 89 * The service class that manages LocationProviders and issues location 90 * updates and alerts. 91 * 92 * {@hide} 93 */ 94public class LocationManagerService extends ILocationManager.Stub implements Runnable { 95 private static final String TAG = "LocationManagerService"; 96 private static final boolean LOCAL_LOGV = false; 97 98 // The last time a location was written, by provider name. 99 private HashMap<String,Long> mLastWriteTime = new HashMap<String,Long>(); 100 101 private static final String ACCESS_FINE_LOCATION = 102 android.Manifest.permission.ACCESS_FINE_LOCATION; 103 private static final String ACCESS_COARSE_LOCATION = 104 android.Manifest.permission.ACCESS_COARSE_LOCATION; 105 private static final String ACCESS_MOCK_LOCATION = 106 android.Manifest.permission.ACCESS_MOCK_LOCATION; 107 private static final String ACCESS_LOCATION_EXTRA_COMMANDS = 108 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS; 109 private static final String INSTALL_LOCATION_PROVIDER = 110 android.Manifest.permission.INSTALL_LOCATION_PROVIDER; 111 112 // Location Providers may sometimes deliver location updates 113 // slightly faster that requested - provide grace period so 114 // we don't unnecessarily filter events that are otherwise on 115 // time 116 private static final int MAX_PROVIDER_SCHEDULING_JITTER = 100; 117 118 // Set of providers that are explicitly enabled 119 private final Set<String> mEnabledProviders = new HashSet<String>(); 120 121 // Set of providers that are explicitly disabled 122 private final Set<String> mDisabledProviders = new HashSet<String>(); 123 124 // Locations, status values, and extras for mock providers 125 private final HashMap<String,MockProvider> mMockProviders = new HashMap<String,MockProvider>(); 126 127 private static boolean sProvidersLoaded = false; 128 129 private final Context mContext; 130 private PackageManager mPackageManager; // final after initialize() 131 private String mNetworkLocationProviderPackageName; // only used on handler thread 132 private String mGeocodeProviderPackageName; // only used on handler thread 133 private GeocoderProxy mGeocodeProvider; 134 private IGpsStatusProvider mGpsStatusProvider; 135 private INetInitiatedListener mNetInitiatedListener; 136 private LocationWorkerHandler mLocationHandler; 137 138 // Cache the real providers for use in addTestProvider() and removeTestProvider() 139 LocationProviderProxy mNetworkLocationProvider; 140 LocationProviderInterface mGpsLocationProvider; 141 142 // Handler messages 143 private static final int MESSAGE_LOCATION_CHANGED = 1; 144 private static final int MESSAGE_PACKAGE_UPDATED = 2; 145 146 // wakelock variables 147 private final static String WAKELOCK_KEY = "LocationManagerService"; 148 private PowerManager.WakeLock mWakeLock = null; 149 private int mPendingBroadcasts; 150 151 /** 152 * List of all receivers. 153 */ 154 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>(); 155 156 157 /** 158 * List of location providers. 159 */ 160 private final ArrayList<LocationProviderInterface> mProviders = 161 new ArrayList<LocationProviderInterface>(); 162 private final HashMap<String, LocationProviderInterface> mProvidersByName 163 = new HashMap<String, LocationProviderInterface>(); 164 165 /** 166 * Object used internally for synchronization 167 */ 168 private final Object mLock = new Object(); 169 170 /** 171 * Mapping from provider name to all its UpdateRecords 172 */ 173 private final HashMap<String,ArrayList<UpdateRecord>> mRecordsByProvider = 174 new HashMap<String,ArrayList<UpdateRecord>>(); 175 176 /** 177 * Temporary filled in when computing min time for a provider. Access is 178 * protected by global lock mLock. 179 */ 180 private final WorkSource mTmpWorkSource = new WorkSource(); 181 182 // Proximity listeners 183 private Receiver mProximityReceiver = null; 184 private ILocationListener mProximityListener = null; 185 private HashMap<PendingIntent,ProximityAlert> mProximityAlerts = 186 new HashMap<PendingIntent,ProximityAlert>(); 187 private HashSet<ProximityAlert> mProximitiesEntered = 188 new HashSet<ProximityAlert>(); 189 190 // Last known location for each provider 191 private HashMap<String,Location> mLastKnownLocation = 192 new HashMap<String,Location>(); 193 194 private int mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE; 195 196 // for Settings change notification 197 private ContentQueryMap mSettings; 198 199 /** 200 * A wrapper class holding either an ILocationListener or a PendingIntent to receive 201 * location updates. 202 */ 203 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished { 204 final ILocationListener mListener; 205 final PendingIntent mPendingIntent; 206 final Object mKey; 207 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>(); 208 209 int mPendingBroadcasts; 210 String mRequiredPermissions; 211 212 Receiver(ILocationListener listener) { 213 mListener = listener; 214 mPendingIntent = null; 215 mKey = listener.asBinder(); 216 } 217 218 Receiver(PendingIntent intent) { 219 mPendingIntent = intent; 220 mListener = null; 221 mKey = intent; 222 } 223 224 @Override 225 public boolean equals(Object otherObj) { 226 if (otherObj instanceof Receiver) { 227 return mKey.equals( 228 ((Receiver)otherObj).mKey); 229 } 230 return false; 231 } 232 233 @Override 234 public int hashCode() { 235 return mKey.hashCode(); 236 } 237 238 @Override 239 public String toString() { 240 String result; 241 if (mListener != null) { 242 result = "Receiver{" 243 + Integer.toHexString(System.identityHashCode(this)) 244 + " Listener " + mKey + "}"; 245 } else { 246 result = "Receiver{" 247 + Integer.toHexString(System.identityHashCode(this)) 248 + " Intent " + mKey + "}"; 249 } 250 result += "mUpdateRecords: " + mUpdateRecords; 251 return result; 252 } 253 254 public boolean isListener() { 255 return mListener != null; 256 } 257 258 public boolean isPendingIntent() { 259 return mPendingIntent != null; 260 } 261 262 public ILocationListener getListener() { 263 if (mListener != null) { 264 return mListener; 265 } 266 throw new IllegalStateException("Request for non-existent listener"); 267 } 268 269 public PendingIntent getPendingIntent() { 270 if (mPendingIntent != null) { 271 return mPendingIntent; 272 } 273 throw new IllegalStateException("Request for non-existent intent"); 274 } 275 276 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) { 277 if (mListener != null) { 278 try { 279 synchronized (this) { 280 // synchronize to ensure incrementPendingBroadcastsLocked() 281 // is called before decrementPendingBroadcasts() 282 mListener.onStatusChanged(provider, status, extras); 283 if (mListener != mProximityListener) { 284 // call this after broadcasting so we do not increment 285 // if we throw an exeption. 286 incrementPendingBroadcastsLocked(); 287 } 288 } 289 } catch (RemoteException e) { 290 return false; 291 } 292 } else { 293 Intent statusChanged = new Intent(); 294 statusChanged.putExtras(extras); 295 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status); 296 try { 297 synchronized (this) { 298 // synchronize to ensure incrementPendingBroadcastsLocked() 299 // is called before decrementPendingBroadcasts() 300 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler, 301 mRequiredPermissions); 302 // call this after broadcasting so we do not increment 303 // if we throw an exeption. 304 incrementPendingBroadcastsLocked(); 305 } 306 } catch (PendingIntent.CanceledException e) { 307 return false; 308 } 309 } 310 return true; 311 } 312 313 public boolean callLocationChangedLocked(Location location) { 314 if (mListener != null) { 315 try { 316 synchronized (this) { 317 // synchronize to ensure incrementPendingBroadcastsLocked() 318 // is called before decrementPendingBroadcasts() 319 mListener.onLocationChanged(location); 320 if (mListener != mProximityListener) { 321 // call this after broadcasting so we do not increment 322 // if we throw an exeption. 323 incrementPendingBroadcastsLocked(); 324 } 325 } 326 } catch (RemoteException e) { 327 return false; 328 } 329 } else { 330 Intent locationChanged = new Intent(); 331 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location); 332 try { 333 synchronized (this) { 334 // synchronize to ensure incrementPendingBroadcastsLocked() 335 // is called before decrementPendingBroadcasts() 336 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler, 337 mRequiredPermissions); 338 // call this after broadcasting so we do not increment 339 // if we throw an exeption. 340 incrementPendingBroadcastsLocked(); 341 } 342 } catch (PendingIntent.CanceledException e) { 343 return false; 344 } 345 } 346 return true; 347 } 348 349 public boolean callProviderEnabledLocked(String provider, boolean enabled) { 350 if (mListener != null) { 351 try { 352 synchronized (this) { 353 // synchronize to ensure incrementPendingBroadcastsLocked() 354 // is called before decrementPendingBroadcasts() 355 if (enabled) { 356 mListener.onProviderEnabled(provider); 357 } else { 358 mListener.onProviderDisabled(provider); 359 } 360 if (mListener != mProximityListener) { 361 // call this after broadcasting so we do not increment 362 // if we throw an exeption. 363 incrementPendingBroadcastsLocked(); 364 } 365 } 366 } catch (RemoteException e) { 367 return false; 368 } 369 } else { 370 Intent providerIntent = new Intent(); 371 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled); 372 try { 373 synchronized (this) { 374 // synchronize to ensure incrementPendingBroadcastsLocked() 375 // is called before decrementPendingBroadcasts() 376 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler, 377 mRequiredPermissions); 378 // call this after broadcasting so we do not increment 379 // if we throw an exeption. 380 incrementPendingBroadcastsLocked(); 381 } 382 } catch (PendingIntent.CanceledException e) { 383 return false; 384 } 385 } 386 return true; 387 } 388 389 @Override 390 public void binderDied() { 391 if (LOCAL_LOGV) { 392 Slog.v(TAG, "Location listener died"); 393 } 394 synchronized (mLock) { 395 removeUpdatesLocked(this); 396 } 397 synchronized (this) { 398 if (mPendingBroadcasts > 0) { 399 LocationManagerService.this.decrementPendingBroadcasts(); 400 mPendingBroadcasts = 0; 401 } 402 } 403 } 404 405 public void onSendFinished(PendingIntent pendingIntent, Intent intent, 406 int resultCode, String resultData, Bundle resultExtras) { 407 synchronized (this) { 408 decrementPendingBroadcastsLocked(); 409 } 410 } 411 412 // this must be called while synchronized by caller in a synchronized block 413 // containing the sending of the broadcaset 414 private void incrementPendingBroadcastsLocked() { 415 if (mPendingBroadcasts++ == 0) { 416 LocationManagerService.this.incrementPendingBroadcasts(); 417 } 418 } 419 420 private void decrementPendingBroadcastsLocked() { 421 if (--mPendingBroadcasts == 0) { 422 LocationManagerService.this.decrementPendingBroadcasts(); 423 } 424 } 425 } 426 427 public void locationCallbackFinished(ILocationListener listener) { 428 //Do not use getReceiver here as that will add the ILocationListener to 429 //the receiver list if it is not found. If it is not found then the 430 //LocationListener was removed when it had a pending broadcast and should 431 //not be added back. 432 IBinder binder = listener.asBinder(); 433 Receiver receiver = mReceivers.get(binder); 434 if (receiver != null) { 435 synchronized (receiver) { 436 // so wakelock calls will succeed 437 long identity = Binder.clearCallingIdentity(); 438 receiver.decrementPendingBroadcastsLocked(); 439 Binder.restoreCallingIdentity(identity); 440 } 441 } 442 } 443 444 private final class SettingsObserver implements Observer { 445 public void update(Observable o, Object arg) { 446 synchronized (mLock) { 447 updateProvidersLocked(); 448 } 449 } 450 } 451 452 private void addProvider(LocationProviderInterface provider) { 453 mProviders.add(provider); 454 mProvidersByName.put(provider.getName(), provider); 455 } 456 457 private void removeProvider(LocationProviderInterface provider) { 458 mProviders.remove(provider); 459 mProvidersByName.remove(provider.getName()); 460 } 461 462 private void loadProviders() { 463 synchronized (mLock) { 464 if (sProvidersLoaded) { 465 return; 466 } 467 468 // Load providers 469 loadProvidersLocked(); 470 sProvidersLoaded = true; 471 } 472 } 473 474 private void loadProvidersLocked() { 475 try { 476 _loadProvidersLocked(); 477 } catch (Exception e) { 478 Slog.e(TAG, "Exception loading providers:", e); 479 } 480 } 481 482 private void _loadProvidersLocked() { 483 // Attempt to load "real" providers first 484 if (GpsLocationProvider.isSupported()) { 485 // Create a gps location provider 486 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this); 487 mGpsStatusProvider = gpsProvider.getGpsStatusProvider(); 488 mNetInitiatedListener = gpsProvider.getNetInitiatedListener(); 489 addProvider(gpsProvider); 490 mGpsLocationProvider = gpsProvider; 491 } 492 493 // create a passive location provider, which is always enabled 494 PassiveProvider passiveProvider = new PassiveProvider(this); 495 addProvider(passiveProvider); 496 mEnabledProviders.add(passiveProvider.getName()); 497 498 // initialize external network location and geocoder services. 499 // The initial value of mNetworkLocationProviderPackageName and 500 // mGeocodeProviderPackageName is just used to determine what 501 // signatures future mNetworkLocationProviderPackageName and 502 // mGeocodeProviderPackageName packages must have. So alternate 503 // providers can be installed under a different package name 504 // so long as they have the same signature as the original 505 // provider packages. 506 if (mNetworkLocationProviderPackageName != null) { 507 String packageName = findBestPackage(LocationProviderProxy.SERVICE_ACTION, 508 mNetworkLocationProviderPackageName); 509 if (packageName != null) { 510 mNetworkLocationProvider = new LocationProviderProxy(mContext, 511 LocationManager.NETWORK_PROVIDER, 512 packageName, mLocationHandler); 513 mNetworkLocationProviderPackageName = packageName; 514 addProvider(mNetworkLocationProvider); 515 } 516 } 517 if (mGeocodeProviderPackageName != null) { 518 String packageName = findBestPackage(GeocoderProxy.SERVICE_ACTION, 519 mGeocodeProviderPackageName); 520 if (packageName != null) { 521 mGeocodeProvider = new GeocoderProxy(mContext, packageName); 522 mGeocodeProviderPackageName = packageName; 523 } 524 } 525 526 updateProvidersLocked(); 527 } 528 529 /** 530 * Pick the best (network location provider or geocode provider) package. 531 * The best package: 532 * - implements serviceIntentName 533 * - has signatures that match that of sigPackageName 534 * - has the highest version value in a meta-data field in the service component 535 */ 536 String findBestPackage(String serviceIntentName, String sigPackageName) { 537 Intent intent = new Intent(serviceIntentName); 538 List<ResolveInfo> infos = mPackageManager.queryIntentServices(intent, 539 PackageManager.GET_META_DATA); 540 if (infos == null) return null; 541 542 int bestVersion = Integer.MIN_VALUE; 543 String bestPackage = null; 544 for (ResolveInfo info : infos) { 545 String packageName = info.serviceInfo.packageName; 546 // check signature 547 if (mPackageManager.checkSignatures(packageName, sigPackageName) != 548 PackageManager.SIGNATURE_MATCH) { 549 Slog.w(TAG, packageName + " implements " + serviceIntentName + 550 " but its signatures don't match those in " + sigPackageName + 551 ", ignoring"); 552 continue; 553 } 554 // read version 555 int version = 0; 556 if (info.serviceInfo.metaData != null) { 557 version = info.serviceInfo.metaData.getInt("version", 0); 558 } 559 if (LOCAL_LOGV) Slog.v(TAG, packageName + " implements " + serviceIntentName + 560 " with version " + version); 561 if (version > bestVersion) { 562 bestVersion = version; 563 bestPackage = packageName; 564 } 565 } 566 567 return bestPackage; 568 } 569 570 /** 571 * @param context the context that the LocationManagerService runs in 572 */ 573 public LocationManagerService(Context context) { 574 super(); 575 mContext = context; 576 Resources resources = context.getResources(); 577 578 mNetworkLocationProviderPackageName = resources.getString( 579 com.android.internal.R.string.config_networkLocationProviderPackageName); 580 mGeocodeProviderPackageName = resources.getString( 581 com.android.internal.R.string.config_geocodeProviderPackageName); 582 583 mPackageMonitor.register(context, null, true); 584 585 if (LOCAL_LOGV) { 586 Slog.v(TAG, "Constructed LocationManager Service"); 587 } 588 } 589 590 void systemReady() { 591 // we defer starting up the service until the system is ready 592 Thread thread = new Thread(null, this, "LocationManagerService"); 593 thread.start(); 594 } 595 596 private void initialize() { 597 // Create a wake lock, needs to be done before calling loadProviders() below 598 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 599 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); 600 mPackageManager = mContext.getPackageManager(); 601 602 // Load providers 603 loadProviders(); 604 605 // Register for Network (Wifi or Mobile) updates 606 IntentFilter intentFilter = new IntentFilter(); 607 intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 608 // Register for Package Manager updates 609 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 610 intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); 611 intentFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); 612 mContext.registerReceiver(mBroadcastReceiver, intentFilter); 613 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 614 mContext.registerReceiver(mBroadcastReceiver, sdFilter); 615 616 // listen for settings changes 617 ContentResolver resolver = mContext.getContentResolver(); 618 Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null, 619 "(" + Settings.System.NAME + "=?)", 620 new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED}, 621 null); 622 mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mLocationHandler); 623 SettingsObserver settingsObserver = new SettingsObserver(); 624 mSettings.addObserver(settingsObserver); 625 } 626 627 public void run() 628 { 629 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 630 Looper.prepare(); 631 mLocationHandler = new LocationWorkerHandler(); 632 initialize(); 633 Looper.loop(); 634 } 635 636 private boolean isAllowedBySettingsLocked(String provider) { 637 if (mEnabledProviders.contains(provider)) { 638 return true; 639 } 640 if (mDisabledProviders.contains(provider)) { 641 return false; 642 } 643 // Use system settings 644 ContentResolver resolver = mContext.getContentResolver(); 645 646 return Settings.Secure.isLocationProviderEnabled(resolver, provider); 647 } 648 649 private String checkPermissionsSafe(String provider, String lastPermission) { 650 if (LocationManager.GPS_PROVIDER.equals(provider) 651 || LocationManager.PASSIVE_PROVIDER.equals(provider)) { 652 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) 653 != PackageManager.PERMISSION_GRANTED) { 654 throw new SecurityException("Provider " + provider 655 + " requires ACCESS_FINE_LOCATION permission"); 656 } 657 return ACCESS_FINE_LOCATION; 658 } 659 660 // Assume any other provider requires the coarse or fine permission. 661 if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) 662 == PackageManager.PERMISSION_GRANTED) { 663 return ACCESS_FINE_LOCATION.equals(lastPermission) 664 ? lastPermission : ACCESS_COARSE_LOCATION; 665 } 666 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) 667 == PackageManager.PERMISSION_GRANTED) { 668 return ACCESS_FINE_LOCATION; 669 } 670 671 throw new SecurityException("Provider " + provider 672 + " requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission"); 673 } 674 675 private boolean isAllowedProviderSafe(String provider) { 676 if ((LocationManager.GPS_PROVIDER.equals(provider) 677 || LocationManager.PASSIVE_PROVIDER.equals(provider)) 678 && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) 679 != PackageManager.PERMISSION_GRANTED)) { 680 return false; 681 } 682 if (LocationManager.NETWORK_PROVIDER.equals(provider) 683 && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) 684 != PackageManager.PERMISSION_GRANTED) 685 && (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) 686 != PackageManager.PERMISSION_GRANTED)) { 687 return false; 688 } 689 690 return true; 691 } 692 693 public List<String> getAllProviders() { 694 try { 695 synchronized (mLock) { 696 return _getAllProvidersLocked(); 697 } 698 } catch (SecurityException se) { 699 throw se; 700 } catch (Exception e) { 701 Slog.e(TAG, "getAllProviders got exception:", e); 702 return null; 703 } 704 } 705 706 private List<String> _getAllProvidersLocked() { 707 if (LOCAL_LOGV) { 708 Slog.v(TAG, "getAllProviders"); 709 } 710 ArrayList<String> out = new ArrayList<String>(mProviders.size()); 711 for (int i = mProviders.size() - 1; i >= 0; i--) { 712 LocationProviderInterface p = mProviders.get(i); 713 out.add(p.getName()); 714 } 715 return out; 716 } 717 718 public List<String> getProviders(Criteria criteria, boolean enabledOnly) { 719 try { 720 synchronized (mLock) { 721 return _getProvidersLocked(criteria, enabledOnly); 722 } 723 } catch (SecurityException se) { 724 throw se; 725 } catch (Exception e) { 726 Slog.e(TAG, "getProviders got exception:", e); 727 return null; 728 } 729 } 730 731 private List<String> _getProvidersLocked(Criteria criteria, boolean enabledOnly) { 732 if (LOCAL_LOGV) { 733 Slog.v(TAG, "getProviders"); 734 } 735 ArrayList<String> out = new ArrayList<String>(mProviders.size()); 736 for (int i = mProviders.size() - 1; i >= 0; i--) { 737 LocationProviderInterface p = mProviders.get(i); 738 String name = p.getName(); 739 if (isAllowedProviderSafe(name)) { 740 if (enabledOnly && !isAllowedBySettingsLocked(name)) { 741 continue; 742 } 743 if (criteria != null && !p.meetsCriteria(criteria)) { 744 continue; 745 } 746 out.add(name); 747 } 748 } 749 return out; 750 } 751 752 /** 753 * Returns the next looser power requirement, in the sequence: 754 * 755 * POWER_LOW -> POWER_MEDIUM -> POWER_HIGH -> NO_REQUIREMENT 756 */ 757 private int nextPower(int power) { 758 switch (power) { 759 case Criteria.POWER_LOW: 760 return Criteria.POWER_MEDIUM; 761 case Criteria.POWER_MEDIUM: 762 return Criteria.POWER_HIGH; 763 case Criteria.POWER_HIGH: 764 return Criteria.NO_REQUIREMENT; 765 case Criteria.NO_REQUIREMENT: 766 default: 767 return Criteria.NO_REQUIREMENT; 768 } 769 } 770 771 /** 772 * Returns the next looser accuracy requirement, in the sequence: 773 * 774 * ACCURACY_FINE -> ACCURACY_APPROXIMATE-> NO_REQUIREMENT 775 */ 776 private int nextAccuracy(int accuracy) { 777 if (accuracy == Criteria.ACCURACY_FINE) { 778 return Criteria.ACCURACY_COARSE; 779 } else { 780 return Criteria.NO_REQUIREMENT; 781 } 782 } 783 784 private class LpPowerComparator implements Comparator<LocationProviderInterface> { 785 public int compare(LocationProviderInterface l1, LocationProviderInterface l2) { 786 // Smaller is better 787 return (l1.getPowerRequirement() - l2.getPowerRequirement()); 788 } 789 790 public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) { 791 return (l1.getPowerRequirement() == l2.getPowerRequirement()); 792 } 793 } 794 795 private class LpAccuracyComparator implements Comparator<LocationProviderInterface> { 796 public int compare(LocationProviderInterface l1, LocationProviderInterface l2) { 797 // Smaller is better 798 return (l1.getAccuracy() - l2.getAccuracy()); 799 } 800 801 public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) { 802 return (l1.getAccuracy() == l2.getAccuracy()); 803 } 804 } 805 806 private class LpCapabilityComparator implements Comparator<LocationProviderInterface> { 807 808 private static final int ALTITUDE_SCORE = 4; 809 private static final int BEARING_SCORE = 4; 810 private static final int SPEED_SCORE = 4; 811 812 private int score(LocationProviderInterface p) { 813 return (p.supportsAltitude() ? ALTITUDE_SCORE : 0) + 814 (p.supportsBearing() ? BEARING_SCORE : 0) + 815 (p.supportsSpeed() ? SPEED_SCORE : 0); 816 } 817 818 public int compare(LocationProviderInterface l1, LocationProviderInterface l2) { 819 return (score(l2) - score(l1)); // Bigger is better 820 } 821 822 public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) { 823 return (score(l1) == score(l2)); 824 } 825 } 826 827 private LocationProviderInterface best(List<String> providerNames) { 828 ArrayList<LocationProviderInterface> providers; 829 synchronized (mLock) { 830 providers = new ArrayList<LocationProviderInterface>(providerNames.size()); 831 for (String name : providerNames) { 832 providers.add(mProvidersByName.get(name)); 833 } 834 } 835 836 if (providers.size() < 2) { 837 return providers.get(0); 838 } 839 840 // First, sort by power requirement 841 Collections.sort(providers, new LpPowerComparator()); 842 int power = providers.get(0).getPowerRequirement(); 843 if (power < providers.get(1).getPowerRequirement()) { 844 return providers.get(0); 845 } 846 847 int idx, size; 848 849 ArrayList<LocationProviderInterface> tmp = new ArrayList<LocationProviderInterface>(); 850 idx = 0; 851 size = providers.size(); 852 while ((idx < size) && (providers.get(idx).getPowerRequirement() == power)) { 853 tmp.add(providers.get(idx)); 854 idx++; 855 } 856 857 // Next, sort by accuracy 858 Collections.sort(tmp, new LpAccuracyComparator()); 859 int acc = tmp.get(0).getAccuracy(); 860 if (acc < tmp.get(1).getAccuracy()) { 861 return tmp.get(0); 862 } 863 864 ArrayList<LocationProviderInterface> tmp2 = new ArrayList<LocationProviderInterface>(); 865 idx = 0; 866 size = tmp.size(); 867 while ((idx < size) && (tmp.get(idx).getAccuracy() == acc)) { 868 tmp2.add(tmp.get(idx)); 869 idx++; 870 } 871 872 // Finally, sort by capability "score" 873 Collections.sort(tmp2, new LpCapabilityComparator()); 874 return tmp2.get(0); 875 } 876 877 /** 878 * Returns the name of the provider that best meets the given criteria. Only providers 879 * that are permitted to be accessed by the calling activity will be 880 * returned. If several providers meet the criteria, the one with the best 881 * accuracy is returned. If no provider meets the criteria, 882 * the criteria are loosened in the following sequence: 883 * 884 * <ul> 885 * <li> power requirement 886 * <li> accuracy 887 * <li> bearing 888 * <li> speed 889 * <li> altitude 890 * </ul> 891 * 892 * <p> Note that the requirement on monetary cost is not removed 893 * in this process. 894 * 895 * @param criteria the criteria that need to be matched 896 * @param enabledOnly if true then only a provider that is currently enabled is returned 897 * @return name of the provider that best matches the requirements 898 */ 899 public String getBestProvider(Criteria criteria, boolean enabledOnly) { 900 List<String> goodProviders = getProviders(criteria, enabledOnly); 901 if (!goodProviders.isEmpty()) { 902 return best(goodProviders).getName(); 903 } 904 905 // Make a copy of the criteria that we can modify 906 criteria = new Criteria(criteria); 907 908 // Loosen power requirement 909 int power = criteria.getPowerRequirement(); 910 while (goodProviders.isEmpty() && (power != Criteria.NO_REQUIREMENT)) { 911 power = nextPower(power); 912 criteria.setPowerRequirement(power); 913 goodProviders = getProviders(criteria, enabledOnly); 914 } 915 if (!goodProviders.isEmpty()) { 916 return best(goodProviders).getName(); 917 } 918 919 // Loosen accuracy requirement 920 int accuracy = criteria.getAccuracy(); 921 while (goodProviders.isEmpty() && (accuracy != Criteria.NO_REQUIREMENT)) { 922 accuracy = nextAccuracy(accuracy); 923 criteria.setAccuracy(accuracy); 924 goodProviders = getProviders(criteria, enabledOnly); 925 } 926 if (!goodProviders.isEmpty()) { 927 return best(goodProviders).getName(); 928 } 929 930 // Remove bearing requirement 931 criteria.setBearingRequired(false); 932 goodProviders = getProviders(criteria, enabledOnly); 933 if (!goodProviders.isEmpty()) { 934 return best(goodProviders).getName(); 935 } 936 937 // Remove speed requirement 938 criteria.setSpeedRequired(false); 939 goodProviders = getProviders(criteria, enabledOnly); 940 if (!goodProviders.isEmpty()) { 941 return best(goodProviders).getName(); 942 } 943 944 // Remove altitude requirement 945 criteria.setAltitudeRequired(false); 946 goodProviders = getProviders(criteria, enabledOnly); 947 if (!goodProviders.isEmpty()) { 948 return best(goodProviders).getName(); 949 } 950 951 return null; 952 } 953 954 public boolean providerMeetsCriteria(String provider, Criteria criteria) { 955 LocationProviderInterface p = mProvidersByName.get(provider); 956 if (p == null) { 957 throw new IllegalArgumentException("provider=" + provider); 958 } 959 return p.meetsCriteria(criteria); 960 } 961 962 private void updateProvidersLocked() { 963 boolean changesMade = false; 964 for (int i = mProviders.size() - 1; i >= 0; i--) { 965 LocationProviderInterface p = mProviders.get(i); 966 boolean isEnabled = p.isEnabled(); 967 String name = p.getName(); 968 boolean shouldBeEnabled = isAllowedBySettingsLocked(name); 969 if (isEnabled && !shouldBeEnabled) { 970 updateProviderListenersLocked(name, false); 971 changesMade = true; 972 } else if (!isEnabled && shouldBeEnabled) { 973 updateProviderListenersLocked(name, true); 974 changesMade = true; 975 } 976 } 977 if (changesMade) { 978 mContext.sendBroadcast(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION)); 979 } 980 } 981 982 private void updateProviderListenersLocked(String provider, boolean enabled) { 983 int listeners = 0; 984 985 LocationProviderInterface p = mProvidersByName.get(provider); 986 if (p == null) { 987 return; 988 } 989 990 ArrayList<Receiver> deadReceivers = null; 991 992 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 993 if (records != null) { 994 final int N = records.size(); 995 for (int i=0; i<N; i++) { 996 UpdateRecord record = records.get(i); 997 // Sends a notification message to the receiver 998 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) { 999 if (deadReceivers == null) { 1000 deadReceivers = new ArrayList<Receiver>(); 1001 } 1002 deadReceivers.add(record.mReceiver); 1003 } 1004 listeners++; 1005 } 1006 } 1007 1008 if (deadReceivers != null) { 1009 for (int i=deadReceivers.size()-1; i>=0; i--) { 1010 removeUpdatesLocked(deadReceivers.get(i)); 1011 } 1012 } 1013 1014 if (enabled) { 1015 p.enable(); 1016 if (listeners > 0) { 1017 p.setMinTime(getMinTimeLocked(provider), mTmpWorkSource); 1018 p.enableLocationTracking(true); 1019 } 1020 } else { 1021 p.enableLocationTracking(false); 1022 p.disable(); 1023 } 1024 } 1025 1026 private long getMinTimeLocked(String provider) { 1027 long minTime = Long.MAX_VALUE; 1028 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 1029 mTmpWorkSource.clear(); 1030 if (records != null) { 1031 for (int i=records.size()-1; i>=0; i--) { 1032 UpdateRecord ur = records.get(i); 1033 long curTime = ur.mMinTime; 1034 if (curTime < minTime) { 1035 minTime = curTime; 1036 } 1037 } 1038 long inclTime = (minTime*3)/2; 1039 for (int i=records.size()-1; i>=0; i--) { 1040 UpdateRecord ur = records.get(i); 1041 if (ur.mMinTime <= inclTime) { 1042 mTmpWorkSource.add(ur.mUid); 1043 } 1044 } 1045 } 1046 return minTime; 1047 } 1048 1049 private class UpdateRecord { 1050 final String mProvider; 1051 final Receiver mReceiver; 1052 final long mMinTime; 1053 final float mMinDistance; 1054 final boolean mSingleShot; 1055 final int mUid; 1056 Location mLastFixBroadcast; 1057 long mLastStatusBroadcast; 1058 1059 /** 1060 * Note: must be constructed with lock held. 1061 */ 1062 UpdateRecord(String provider, long minTime, float minDistance, boolean singleShot, 1063 Receiver receiver, int uid) { 1064 mProvider = provider; 1065 mReceiver = receiver; 1066 mMinTime = minTime; 1067 mMinDistance = minDistance; 1068 mSingleShot = singleShot; 1069 mUid = uid; 1070 1071 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 1072 if (records == null) { 1073 records = new ArrayList<UpdateRecord>(); 1074 mRecordsByProvider.put(provider, records); 1075 } 1076 if (!records.contains(this)) { 1077 records.add(this); 1078 } 1079 } 1080 1081 /** 1082 * Method to be called when a record will no longer be used. Calling this multiple times 1083 * must have the same effect as calling it once. 1084 */ 1085 void disposeLocked() { 1086 ArrayList<UpdateRecord> records = mRecordsByProvider.get(this.mProvider); 1087 if (records != null) { 1088 records.remove(this); 1089 } 1090 } 1091 1092 @Override 1093 public String toString() { 1094 return "UpdateRecord{" 1095 + Integer.toHexString(System.identityHashCode(this)) 1096 + " mProvider: " + mProvider + " mUid: " + mUid + "}"; 1097 } 1098 1099 void dump(PrintWriter pw, String prefix) { 1100 pw.println(prefix + this); 1101 pw.println(prefix + "mProvider=" + mProvider + " mReceiver=" + mReceiver); 1102 pw.println(prefix + "mMinTime=" + mMinTime + " mMinDistance=" + mMinDistance); 1103 pw.println(prefix + "mSingleShot=" + mSingleShot); 1104 pw.println(prefix + "mUid=" + mUid); 1105 pw.println(prefix + "mLastFixBroadcast:"); 1106 if (mLastFixBroadcast != null) { 1107 mLastFixBroadcast.dump(new PrintWriterPrinter(pw), prefix + " "); 1108 } 1109 pw.println(prefix + "mLastStatusBroadcast=" + mLastStatusBroadcast); 1110 } 1111 } 1112 1113 private Receiver getReceiver(ILocationListener listener) { 1114 IBinder binder = listener.asBinder(); 1115 Receiver receiver = mReceivers.get(binder); 1116 if (receiver == null) { 1117 receiver = new Receiver(listener); 1118 mReceivers.put(binder, receiver); 1119 1120 try { 1121 if (receiver.isListener()) { 1122 receiver.getListener().asBinder().linkToDeath(receiver, 0); 1123 } 1124 } catch (RemoteException e) { 1125 Slog.e(TAG, "linkToDeath failed:", e); 1126 return null; 1127 } 1128 } 1129 return receiver; 1130 } 1131 1132 private Receiver getReceiver(PendingIntent intent) { 1133 Receiver receiver = mReceivers.get(intent); 1134 if (receiver == null) { 1135 receiver = new Receiver(intent); 1136 mReceivers.put(intent, receiver); 1137 } 1138 return receiver; 1139 } 1140 1141 private boolean providerHasListener(String provider, int uid, Receiver excludedReceiver) { 1142 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 1143 if (records != null) { 1144 for (int i = records.size() - 1; i >= 0; i--) { 1145 UpdateRecord record = records.get(i); 1146 if (record.mUid == uid && record.mReceiver != excludedReceiver) { 1147 return true; 1148 } 1149 } 1150 } 1151 for (ProximityAlert alert : mProximityAlerts.values()) { 1152 if (alert.mUid == uid) { 1153 return true; 1154 } 1155 } 1156 return false; 1157 } 1158 1159 public void requestLocationUpdates(String provider, Criteria criteria, 1160 long minTime, float minDistance, boolean singleShot, ILocationListener listener) { 1161 if (criteria != null) { 1162 // FIXME - should we consider using multiple providers simultaneously 1163 // rather than only the best one? 1164 // Should we do anything different for single shot fixes? 1165 provider = getBestProvider(criteria, true); 1166 if (provider == null) { 1167 throw new IllegalArgumentException("no providers found for criteria"); 1168 } 1169 } 1170 try { 1171 synchronized (mLock) { 1172 requestLocationUpdatesLocked(provider, minTime, minDistance, singleShot, 1173 getReceiver(listener)); 1174 } 1175 } catch (SecurityException se) { 1176 throw se; 1177 } catch (IllegalArgumentException iae) { 1178 throw iae; 1179 } catch (Exception e) { 1180 Slog.e(TAG, "requestUpdates got exception:", e); 1181 } 1182 } 1183 1184 void validatePendingIntent(PendingIntent intent) { 1185 if (intent.isTargetedToPackage()) { 1186 return; 1187 } 1188 Slog.i(TAG, "Given Intent does not require a specific package: " 1189 + intent); 1190 // XXX we should really throw a security exception, if the caller's 1191 // targetSdkVersion is high enough. 1192 //throw new SecurityException("Given Intent does not require a specific package: " 1193 // + intent); 1194 } 1195 1196 public void requestLocationUpdatesPI(String provider, Criteria criteria, 1197 long minTime, float minDistance, boolean singleShot, PendingIntent intent) { 1198 validatePendingIntent(intent); 1199 if (criteria != null) { 1200 // FIXME - should we consider using multiple providers simultaneously 1201 // rather than only the best one? 1202 // Should we do anything different for single shot fixes? 1203 provider = getBestProvider(criteria, true); 1204 if (provider == null) { 1205 throw new IllegalArgumentException("no providers found for criteria"); 1206 } 1207 } 1208 try { 1209 synchronized (mLock) { 1210 requestLocationUpdatesLocked(provider, minTime, minDistance, singleShot, 1211 getReceiver(intent)); 1212 } 1213 } catch (SecurityException se) { 1214 throw se; 1215 } catch (IllegalArgumentException iae) { 1216 throw iae; 1217 } catch (Exception e) { 1218 Slog.e(TAG, "requestUpdates got exception:", e); 1219 } 1220 } 1221 1222 private void requestLocationUpdatesLocked(String provider, long minTime, float minDistance, 1223 boolean singleShot, Receiver receiver) { 1224 1225 LocationProviderInterface p = mProvidersByName.get(provider); 1226 if (p == null) { 1227 throw new IllegalArgumentException("requested provider " + provider + 1228 " doesn't exisit"); 1229 } 1230 receiver.mRequiredPermissions = checkPermissionsSafe(provider, 1231 receiver.mRequiredPermissions); 1232 1233 // so wakelock calls will succeed 1234 final int callingPid = Binder.getCallingPid(); 1235 final int callingUid = Binder.getCallingUid(); 1236 boolean newUid = !providerHasListener(provider, callingUid, null); 1237 long identity = Binder.clearCallingIdentity(); 1238 try { 1239 UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, singleShot, 1240 receiver, callingUid); 1241 UpdateRecord oldRecord = receiver.mUpdateRecords.put(provider, r); 1242 if (oldRecord != null) { 1243 oldRecord.disposeLocked(); 1244 } 1245 1246 if (newUid) { 1247 p.addListener(callingUid); 1248 } 1249 1250 boolean isProviderEnabled = isAllowedBySettingsLocked(provider); 1251 if (isProviderEnabled) { 1252 long minTimeForProvider = getMinTimeLocked(provider); 1253 Slog.i(TAG, "request " + provider + " (pid " + callingPid + ") " + minTime + 1254 " " + minTimeForProvider + (singleShot ? " (singleshot)" : "")); 1255 p.setMinTime(minTimeForProvider, mTmpWorkSource); 1256 // try requesting single shot if singleShot is true, and fall back to 1257 // regular location tracking if requestSingleShotFix() is not supported 1258 if (!singleShot || !p.requestSingleShotFix()) { 1259 p.enableLocationTracking(true); 1260 } 1261 } else { 1262 // Notify the listener that updates are currently disabled 1263 receiver.callProviderEnabledLocked(provider, false); 1264 } 1265 if (LOCAL_LOGV) { 1266 Slog.v(TAG, "_requestLocationUpdates: provider = " + provider + " listener = " + receiver); 1267 } 1268 } finally { 1269 Binder.restoreCallingIdentity(identity); 1270 } 1271 } 1272 1273 public void removeUpdates(ILocationListener listener) { 1274 try { 1275 synchronized (mLock) { 1276 removeUpdatesLocked(getReceiver(listener)); 1277 } 1278 } catch (SecurityException se) { 1279 throw se; 1280 } catch (IllegalArgumentException iae) { 1281 throw iae; 1282 } catch (Exception e) { 1283 Slog.e(TAG, "removeUpdates got exception:", e); 1284 } 1285 } 1286 1287 public void removeUpdatesPI(PendingIntent intent) { 1288 try { 1289 synchronized (mLock) { 1290 removeUpdatesLocked(getReceiver(intent)); 1291 } 1292 } catch (SecurityException se) { 1293 throw se; 1294 } catch (IllegalArgumentException iae) { 1295 throw iae; 1296 } catch (Exception e) { 1297 Slog.e(TAG, "removeUpdates got exception:", e); 1298 } 1299 } 1300 1301 private void removeUpdatesLocked(Receiver receiver) { 1302 if (LOCAL_LOGV) { 1303 Slog.v(TAG, "_removeUpdates: listener = " + receiver); 1304 } 1305 1306 // so wakelock calls will succeed 1307 final int callingPid = Binder.getCallingPid(); 1308 final int callingUid = Binder.getCallingUid(); 1309 long identity = Binder.clearCallingIdentity(); 1310 try { 1311 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) { 1312 receiver.getListener().asBinder().unlinkToDeath(receiver, 0); 1313 synchronized(receiver) { 1314 if(receiver.mPendingBroadcasts > 0) { 1315 decrementPendingBroadcasts(); 1316 receiver.mPendingBroadcasts = 0; 1317 } 1318 } 1319 } 1320 1321 // Record which providers were associated with this listener 1322 HashSet<String> providers = new HashSet<String>(); 1323 HashMap<String,UpdateRecord> oldRecords = receiver.mUpdateRecords; 1324 if (oldRecords != null) { 1325 // Call dispose() on the obsolete update records. 1326 for (UpdateRecord record : oldRecords.values()) { 1327 if (!providerHasListener(record.mProvider, callingUid, receiver)) { 1328 LocationProviderInterface p = mProvidersByName.get(record.mProvider); 1329 if (p != null) { 1330 p.removeListener(callingUid); 1331 } 1332 } 1333 record.disposeLocked(); 1334 } 1335 // Accumulate providers 1336 providers.addAll(oldRecords.keySet()); 1337 } 1338 1339 // See if the providers associated with this listener have any 1340 // other listeners; if one does, inform it of the new smallest minTime 1341 // value; if one does not, disable location tracking for it 1342 for (String provider : providers) { 1343 // If provider is already disabled, don't need to do anything 1344 if (!isAllowedBySettingsLocked(provider)) { 1345 continue; 1346 } 1347 1348 boolean hasOtherListener = false; 1349 ArrayList<UpdateRecord> recordsForProvider = mRecordsByProvider.get(provider); 1350 if (recordsForProvider != null && recordsForProvider.size() > 0) { 1351 hasOtherListener = true; 1352 } 1353 1354 LocationProviderInterface p = mProvidersByName.get(provider); 1355 if (p != null) { 1356 if (hasOtherListener) { 1357 long minTime = getMinTimeLocked(provider); 1358 Slog.i(TAG, "remove " + provider + " (pid " + callingPid + 1359 "), next minTime = " + minTime); 1360 p.setMinTime(minTime, mTmpWorkSource); 1361 } else { 1362 Slog.i(TAG, "remove " + provider + " (pid " + callingPid + 1363 "), disabled"); 1364 p.enableLocationTracking(false); 1365 } 1366 } 1367 } 1368 } finally { 1369 Binder.restoreCallingIdentity(identity); 1370 } 1371 } 1372 1373 public boolean addGpsStatusListener(IGpsStatusListener listener) { 1374 if (mGpsStatusProvider == null) { 1375 return false; 1376 } 1377 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) != 1378 PackageManager.PERMISSION_GRANTED) { 1379 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); 1380 } 1381 1382 try { 1383 mGpsStatusProvider.addGpsStatusListener(listener); 1384 } catch (RemoteException e) { 1385 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e); 1386 return false; 1387 } 1388 return true; 1389 } 1390 1391 public void removeGpsStatusListener(IGpsStatusListener listener) { 1392 synchronized (mLock) { 1393 try { 1394 mGpsStatusProvider.removeGpsStatusListener(listener); 1395 } catch (Exception e) { 1396 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e); 1397 } 1398 } 1399 } 1400 1401 public boolean sendExtraCommand(String provider, String command, Bundle extras) { 1402 if (provider == null) { 1403 // throw NullPointerException to remain compatible with previous implementation 1404 throw new NullPointerException(); 1405 } 1406 1407 // first check for permission to the provider 1408 checkPermissionsSafe(provider, null); 1409 // and check for ACCESS_LOCATION_EXTRA_COMMANDS 1410 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS) 1411 != PackageManager.PERMISSION_GRANTED)) { 1412 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission"); 1413 } 1414 1415 synchronized (mLock) { 1416 LocationProviderInterface p = mProvidersByName.get(provider); 1417 if (p == null) { 1418 return false; 1419 } 1420 1421 return p.sendExtraCommand(command, extras); 1422 } 1423 } 1424 1425 public boolean sendNiResponse(int notifId, int userResponse) 1426 { 1427 if (Binder.getCallingUid() != Process.myUid()) { 1428 throw new SecurityException( 1429 "calling sendNiResponse from outside of the system is not allowed"); 1430 } 1431 try { 1432 return mNetInitiatedListener.sendNiResponse(notifId, userResponse); 1433 } 1434 catch (RemoteException e) 1435 { 1436 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse"); 1437 return false; 1438 } 1439 } 1440 1441 class ProximityAlert { 1442 final int mUid; 1443 final double mLatitude; 1444 final double mLongitude; 1445 final float mRadius; 1446 final long mExpiration; 1447 final PendingIntent mIntent; 1448 final Location mLocation; 1449 1450 public ProximityAlert(int uid, double latitude, double longitude, 1451 float radius, long expiration, PendingIntent intent) { 1452 mUid = uid; 1453 mLatitude = latitude; 1454 mLongitude = longitude; 1455 mRadius = radius; 1456 mExpiration = expiration; 1457 mIntent = intent; 1458 1459 mLocation = new Location(""); 1460 mLocation.setLatitude(latitude); 1461 mLocation.setLongitude(longitude); 1462 } 1463 1464 long getExpiration() { 1465 return mExpiration; 1466 } 1467 1468 PendingIntent getIntent() { 1469 return mIntent; 1470 } 1471 1472 boolean isInProximity(double latitude, double longitude, float accuracy) { 1473 Location loc = new Location(""); 1474 loc.setLatitude(latitude); 1475 loc.setLongitude(longitude); 1476 1477 double radius = loc.distanceTo(mLocation); 1478 return radius <= Math.max(mRadius,accuracy); 1479 } 1480 1481 @Override 1482 public String toString() { 1483 return "ProximityAlert{" 1484 + Integer.toHexString(System.identityHashCode(this)) 1485 + " uid " + mUid + mIntent + "}"; 1486 } 1487 1488 void dump(PrintWriter pw, String prefix) { 1489 pw.println(prefix + this); 1490 pw.println(prefix + "mLatitude=" + mLatitude + " mLongitude=" + mLongitude); 1491 pw.println(prefix + "mRadius=" + mRadius + " mExpiration=" + mExpiration); 1492 pw.println(prefix + "mIntent=" + mIntent); 1493 pw.println(prefix + "mLocation:"); 1494 mLocation.dump(new PrintWriterPrinter(pw), prefix + " "); 1495 } 1496 } 1497 1498 // Listener for receiving locations to trigger proximity alerts 1499 class ProximityListener extends ILocationListener.Stub implements PendingIntent.OnFinished { 1500 1501 boolean isGpsAvailable = false; 1502 1503 // Note: this is called with the lock held. 1504 public void onLocationChanged(Location loc) { 1505 1506 // If Gps is available, then ignore updates from NetworkLocationProvider 1507 if (loc.getProvider().equals(LocationManager.GPS_PROVIDER)) { 1508 isGpsAvailable = true; 1509 } 1510 if (isGpsAvailable && loc.getProvider().equals(LocationManager.NETWORK_PROVIDER)) { 1511 return; 1512 } 1513 1514 // Process proximity alerts 1515 long now = System.currentTimeMillis(); 1516 double latitude = loc.getLatitude(); 1517 double longitude = loc.getLongitude(); 1518 float accuracy = loc.getAccuracy(); 1519 ArrayList<PendingIntent> intentsToRemove = null; 1520 1521 for (ProximityAlert alert : mProximityAlerts.values()) { 1522 PendingIntent intent = alert.getIntent(); 1523 long expiration = alert.getExpiration(); 1524 1525 if ((expiration == -1) || (now <= expiration)) { 1526 boolean entered = mProximitiesEntered.contains(alert); 1527 boolean inProximity = 1528 alert.isInProximity(latitude, longitude, accuracy); 1529 if (!entered && inProximity) { 1530 if (LOCAL_LOGV) { 1531 Slog.v(TAG, "Entered alert"); 1532 } 1533 mProximitiesEntered.add(alert); 1534 Intent enteredIntent = new Intent(); 1535 enteredIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true); 1536 try { 1537 synchronized (this) { 1538 // synchronize to ensure incrementPendingBroadcasts() 1539 // is called before decrementPendingBroadcasts() 1540 intent.send(mContext, 0, enteredIntent, this, mLocationHandler, 1541 ACCESS_FINE_LOCATION); 1542 // call this after broadcasting so we do not increment 1543 // if we throw an exeption. 1544 incrementPendingBroadcasts(); 1545 } 1546 } catch (PendingIntent.CanceledException e) { 1547 if (LOCAL_LOGV) { 1548 Slog.v(TAG, "Canceled proximity alert: " + alert, e); 1549 } 1550 if (intentsToRemove == null) { 1551 intentsToRemove = new ArrayList<PendingIntent>(); 1552 } 1553 intentsToRemove.add(intent); 1554 } 1555 } else if (entered && !inProximity) { 1556 if (LOCAL_LOGV) { 1557 Slog.v(TAG, "Exited alert"); 1558 } 1559 mProximitiesEntered.remove(alert); 1560 Intent exitedIntent = new Intent(); 1561 exitedIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false); 1562 try { 1563 synchronized (this) { 1564 // synchronize to ensure incrementPendingBroadcasts() 1565 // is called before decrementPendingBroadcasts() 1566 intent.send(mContext, 0, exitedIntent, this, mLocationHandler, 1567 ACCESS_FINE_LOCATION); 1568 // call this after broadcasting so we do not increment 1569 // if we throw an exeption. 1570 incrementPendingBroadcasts(); 1571 } 1572 } catch (PendingIntent.CanceledException e) { 1573 if (LOCAL_LOGV) { 1574 Slog.v(TAG, "Canceled proximity alert: " + alert, e); 1575 } 1576 if (intentsToRemove == null) { 1577 intentsToRemove = new ArrayList<PendingIntent>(); 1578 } 1579 intentsToRemove.add(intent); 1580 } 1581 } 1582 } else { 1583 // Mark alert for expiration 1584 if (LOCAL_LOGV) { 1585 Slog.v(TAG, "Expiring proximity alert: " + alert); 1586 } 1587 if (intentsToRemove == null) { 1588 intentsToRemove = new ArrayList<PendingIntent>(); 1589 } 1590 intentsToRemove.add(alert.getIntent()); 1591 } 1592 } 1593 1594 // Remove expired alerts 1595 if (intentsToRemove != null) { 1596 for (PendingIntent i : intentsToRemove) { 1597 ProximityAlert alert = mProximityAlerts.get(i); 1598 mProximitiesEntered.remove(alert); 1599 removeProximityAlertLocked(i); 1600 } 1601 } 1602 } 1603 1604 // Note: this is called with the lock held. 1605 public void onProviderDisabled(String provider) { 1606 if (provider.equals(LocationManager.GPS_PROVIDER)) { 1607 isGpsAvailable = false; 1608 } 1609 } 1610 1611 // Note: this is called with the lock held. 1612 public void onProviderEnabled(String provider) { 1613 // ignore 1614 } 1615 1616 // Note: this is called with the lock held. 1617 public void onStatusChanged(String provider, int status, Bundle extras) { 1618 if ((provider.equals(LocationManager.GPS_PROVIDER)) && 1619 (status != LocationProvider.AVAILABLE)) { 1620 isGpsAvailable = false; 1621 } 1622 } 1623 1624 public void onSendFinished(PendingIntent pendingIntent, Intent intent, 1625 int resultCode, String resultData, Bundle resultExtras) { 1626 // synchronize to ensure incrementPendingBroadcasts() 1627 // is called before decrementPendingBroadcasts() 1628 synchronized (this) { 1629 decrementPendingBroadcasts(); 1630 } 1631 } 1632 } 1633 1634 public void addProximityAlert(double latitude, double longitude, 1635 float radius, long expiration, PendingIntent intent) { 1636 validatePendingIntent(intent); 1637 try { 1638 synchronized (mLock) { 1639 addProximityAlertLocked(latitude, longitude, radius, expiration, intent); 1640 } 1641 } catch (SecurityException se) { 1642 throw se; 1643 } catch (IllegalArgumentException iae) { 1644 throw iae; 1645 } catch (Exception e) { 1646 Slog.e(TAG, "addProximityAlert got exception:", e); 1647 } 1648 } 1649 1650 private void addProximityAlertLocked(double latitude, double longitude, 1651 float radius, long expiration, PendingIntent intent) { 1652 if (LOCAL_LOGV) { 1653 Slog.v(TAG, "addProximityAlert: latitude = " + latitude + 1654 ", longitude = " + longitude + 1655 ", expiration = " + expiration + 1656 ", intent = " + intent); 1657 } 1658 1659 // Require ability to access all providers for now 1660 if (!isAllowedProviderSafe(LocationManager.GPS_PROVIDER) || 1661 !isAllowedProviderSafe(LocationManager.NETWORK_PROVIDER)) { 1662 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); 1663 } 1664 1665 if (expiration != -1) { 1666 expiration += System.currentTimeMillis(); 1667 } 1668 ProximityAlert alert = new ProximityAlert(Binder.getCallingUid(), 1669 latitude, longitude, radius, expiration, intent); 1670 mProximityAlerts.put(intent, alert); 1671 1672 if (mProximityReceiver == null) { 1673 mProximityListener = new ProximityListener(); 1674 mProximityReceiver = new Receiver(mProximityListener); 1675 1676 for (int i = mProviders.size() - 1; i >= 0; i--) { 1677 LocationProviderInterface provider = mProviders.get(i); 1678 requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, 1679 false, mProximityReceiver); 1680 } 1681 } 1682 } 1683 1684 public void removeProximityAlert(PendingIntent intent) { 1685 try { 1686 synchronized (mLock) { 1687 removeProximityAlertLocked(intent); 1688 } 1689 } catch (SecurityException se) { 1690 throw se; 1691 } catch (IllegalArgumentException iae) { 1692 throw iae; 1693 } catch (Exception e) { 1694 Slog.e(TAG, "removeProximityAlert got exception:", e); 1695 } 1696 } 1697 1698 private void removeProximityAlertLocked(PendingIntent intent) { 1699 if (LOCAL_LOGV) { 1700 Slog.v(TAG, "removeProximityAlert: intent = " + intent); 1701 } 1702 1703 mProximityAlerts.remove(intent); 1704 if (mProximityAlerts.size() == 0) { 1705 if (mProximityReceiver != null) { 1706 removeUpdatesLocked(mProximityReceiver); 1707 } 1708 mProximityReceiver = null; 1709 mProximityListener = null; 1710 } 1711 } 1712 1713 /** 1714 * @return null if the provider does not exist 1715 * @throws SecurityException if the provider is not allowed to be 1716 * accessed by the caller 1717 */ 1718 public Bundle getProviderInfo(String provider) { 1719 try { 1720 synchronized (mLock) { 1721 return _getProviderInfoLocked(provider); 1722 } 1723 } catch (SecurityException se) { 1724 throw se; 1725 } catch (IllegalArgumentException iae) { 1726 throw iae; 1727 } catch (Exception e) { 1728 Slog.e(TAG, "_getProviderInfo got exception:", e); 1729 return null; 1730 } 1731 } 1732 1733 private Bundle _getProviderInfoLocked(String provider) { 1734 LocationProviderInterface p = mProvidersByName.get(provider); 1735 if (p == null) { 1736 return null; 1737 } 1738 1739 checkPermissionsSafe(provider, null); 1740 1741 Bundle b = new Bundle(); 1742 b.putBoolean("network", p.requiresNetwork()); 1743 b.putBoolean("satellite", p.requiresSatellite()); 1744 b.putBoolean("cell", p.requiresCell()); 1745 b.putBoolean("cost", p.hasMonetaryCost()); 1746 b.putBoolean("altitude", p.supportsAltitude()); 1747 b.putBoolean("speed", p.supportsSpeed()); 1748 b.putBoolean("bearing", p.supportsBearing()); 1749 b.putInt("power", p.getPowerRequirement()); 1750 b.putInt("accuracy", p.getAccuracy()); 1751 1752 return b; 1753 } 1754 1755 public boolean isProviderEnabled(String provider) { 1756 try { 1757 synchronized (mLock) { 1758 return _isProviderEnabledLocked(provider); 1759 } 1760 } catch (SecurityException se) { 1761 throw se; 1762 } catch (Exception e) { 1763 Slog.e(TAG, "isProviderEnabled got exception:", e); 1764 return false; 1765 } 1766 } 1767 1768 public void reportLocation(Location location, boolean passive) { 1769 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER) 1770 != PackageManager.PERMISSION_GRANTED) { 1771 throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission"); 1772 } 1773 1774 mLocationHandler.removeMessages(MESSAGE_LOCATION_CHANGED, location); 1775 Message m = Message.obtain(mLocationHandler, MESSAGE_LOCATION_CHANGED, location); 1776 m.arg1 = (passive ? 1 : 0); 1777 mLocationHandler.sendMessageAtFrontOfQueue(m); 1778 } 1779 1780 private boolean _isProviderEnabledLocked(String provider) { 1781 checkPermissionsSafe(provider, null); 1782 1783 LocationProviderInterface p = mProvidersByName.get(provider); 1784 if (p == null) { 1785 return false; 1786 } 1787 return isAllowedBySettingsLocked(provider); 1788 } 1789 1790 public Location getLastKnownLocation(String provider) { 1791 if (LOCAL_LOGV) { 1792 Slog.v(TAG, "getLastKnownLocation: " + provider); 1793 } 1794 try { 1795 synchronized (mLock) { 1796 return _getLastKnownLocationLocked(provider); 1797 } 1798 } catch (SecurityException se) { 1799 throw se; 1800 } catch (Exception e) { 1801 Slog.e(TAG, "getLastKnownLocation got exception:", e); 1802 return null; 1803 } 1804 } 1805 1806 private Location _getLastKnownLocationLocked(String provider) { 1807 checkPermissionsSafe(provider, null); 1808 1809 LocationProviderInterface p = mProvidersByName.get(provider); 1810 if (p == null) { 1811 return null; 1812 } 1813 1814 if (!isAllowedBySettingsLocked(provider)) { 1815 return null; 1816 } 1817 1818 return mLastKnownLocation.get(provider); 1819 } 1820 1821 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) { 1822 // Always broadcast the first update 1823 if (lastLoc == null) { 1824 return true; 1825 } 1826 1827 // Check whether sufficient time has passed 1828 long minTime = record.mMinTime; 1829 if (loc.getTime() - lastLoc.getTime() < minTime - MAX_PROVIDER_SCHEDULING_JITTER) { 1830 return false; 1831 } 1832 1833 // Check whether sufficient distance has been traveled 1834 double minDistance = record.mMinDistance; 1835 if (minDistance > 0.0) { 1836 if (loc.distanceTo(lastLoc) <= minDistance) { 1837 return false; 1838 } 1839 } 1840 1841 return true; 1842 } 1843 1844 private void handleLocationChangedLocked(Location location, boolean passive) { 1845 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider()); 1846 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 1847 if (records == null || records.size() == 0) { 1848 return; 1849 } 1850 1851 LocationProviderInterface p = mProvidersByName.get(provider); 1852 if (p == null) { 1853 return; 1854 } 1855 1856 // Update last known location for provider 1857 Location lastLocation = mLastKnownLocation.get(provider); 1858 if (lastLocation == null) { 1859 mLastKnownLocation.put(provider, new Location(location)); 1860 } else { 1861 lastLocation.set(location); 1862 } 1863 1864 // Fetch latest status update time 1865 long newStatusUpdateTime = p.getStatusUpdateTime(); 1866 1867 // Get latest status 1868 Bundle extras = new Bundle(); 1869 int status = p.getStatus(extras); 1870 1871 ArrayList<Receiver> deadReceivers = null; 1872 1873 // Broadcast location or status to all listeners 1874 final int N = records.size(); 1875 for (int i=0; i<N; i++) { 1876 UpdateRecord r = records.get(i); 1877 Receiver receiver = r.mReceiver; 1878 boolean receiverDead = false; 1879 1880 Location lastLoc = r.mLastFixBroadcast; 1881 if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) { 1882 if (lastLoc == null) { 1883 lastLoc = new Location(location); 1884 r.mLastFixBroadcast = lastLoc; 1885 } else { 1886 lastLoc.set(location); 1887 } 1888 if (!receiver.callLocationChangedLocked(location)) { 1889 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver); 1890 receiverDead = true; 1891 } 1892 } 1893 1894 long prevStatusUpdateTime = r.mLastStatusBroadcast; 1895 if ((newStatusUpdateTime > prevStatusUpdateTime) && 1896 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) { 1897 1898 r.mLastStatusBroadcast = newStatusUpdateTime; 1899 if (!receiver.callStatusChangedLocked(provider, status, extras)) { 1900 receiverDead = true; 1901 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver); 1902 } 1903 } 1904 1905 // remove receiver if it is dead or we just processed a single shot request 1906 if (receiverDead || r.mSingleShot) { 1907 if (deadReceivers == null) { 1908 deadReceivers = new ArrayList<Receiver>(); 1909 } 1910 if (!deadReceivers.contains(receiver)) { 1911 deadReceivers.add(receiver); 1912 } 1913 } 1914 } 1915 1916 if (deadReceivers != null) { 1917 for (int i=deadReceivers.size()-1; i>=0; i--) { 1918 removeUpdatesLocked(deadReceivers.get(i)); 1919 } 1920 } 1921 } 1922 1923 private class LocationWorkerHandler extends Handler { 1924 1925 @Override 1926 public void handleMessage(Message msg) { 1927 try { 1928 if (msg.what == MESSAGE_LOCATION_CHANGED) { 1929 // log("LocationWorkerHandler: MESSAGE_LOCATION_CHANGED!"); 1930 1931 synchronized (mLock) { 1932 Location location = (Location) msg.obj; 1933 String provider = location.getProvider(); 1934 boolean passive = (msg.arg1 == 1); 1935 1936 if (!passive) { 1937 // notify other providers of the new location 1938 for (int i = mProviders.size() - 1; i >= 0; i--) { 1939 LocationProviderInterface p = mProviders.get(i); 1940 if (!provider.equals(p.getName())) { 1941 p.updateLocation(location); 1942 } 1943 } 1944 } 1945 1946 if (isAllowedBySettingsLocked(provider)) { 1947 handleLocationChangedLocked(location, passive); 1948 } 1949 } 1950 } else if (msg.what == MESSAGE_PACKAGE_UPDATED) { 1951 String packageName = (String) msg.obj; 1952 1953 // reconnect to external providers if there is a better package 1954 if (mNetworkLocationProviderPackageName != null && 1955 mPackageManager.resolveService( 1956 new Intent(LocationProviderProxy.SERVICE_ACTION) 1957 .setPackage(packageName), 0) != null) { 1958 // package implements service, perform full check 1959 String bestPackage = findBestPackage( 1960 LocationProviderProxy.SERVICE_ACTION, 1961 mNetworkLocationProviderPackageName); 1962 if (packageName.equals(bestPackage)) { 1963 mNetworkLocationProvider.reconnect(bestPackage); 1964 mNetworkLocationProviderPackageName = packageName; 1965 } 1966 } 1967 if (mGeocodeProviderPackageName != null && 1968 mPackageManager.resolveService( 1969 new Intent(GeocoderProxy.SERVICE_ACTION) 1970 .setPackage(packageName), 0) != null) { 1971 // package implements service, perform full check 1972 String bestPackage = findBestPackage( 1973 GeocoderProxy.SERVICE_ACTION, 1974 mGeocodeProviderPackageName); 1975 if (packageName.equals(bestPackage)) { 1976 mGeocodeProvider.reconnect(bestPackage); 1977 mGeocodeProviderPackageName = packageName; 1978 } 1979 } 1980 } 1981 } catch (Exception e) { 1982 // Log, don't crash! 1983 Slog.e(TAG, "Exception in LocationWorkerHandler.handleMessage:", e); 1984 } 1985 } 1986 } 1987 1988 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 1989 @Override 1990 public void onReceive(Context context, Intent intent) { 1991 String action = intent.getAction(); 1992 boolean queryRestart = action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART); 1993 if (queryRestart 1994 || action.equals(Intent.ACTION_PACKAGE_REMOVED) 1995 || action.equals(Intent.ACTION_PACKAGE_RESTARTED) 1996 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { 1997 synchronized (mLock) { 1998 int uidList[] = null; 1999 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { 2000 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 2001 } else { 2002 uidList = new int[]{intent.getIntExtra(Intent.EXTRA_UID, -1)}; 2003 } 2004 if (uidList == null || uidList.length == 0) { 2005 return; 2006 } 2007 for (int uid : uidList) { 2008 if (uid >= 0) { 2009 ArrayList<Receiver> removedRecs = null; 2010 for (ArrayList<UpdateRecord> i : mRecordsByProvider.values()) { 2011 for (int j=i.size()-1; j>=0; j--) { 2012 UpdateRecord ur = i.get(j); 2013 if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) { 2014 if (queryRestart) { 2015 setResultCode(Activity.RESULT_OK); 2016 return; 2017 } 2018 if (removedRecs == null) { 2019 removedRecs = new ArrayList<Receiver>(); 2020 } 2021 if (!removedRecs.contains(ur.mReceiver)) { 2022 removedRecs.add(ur.mReceiver); 2023 } 2024 } 2025 } 2026 } 2027 ArrayList<ProximityAlert> removedAlerts = null; 2028 for (ProximityAlert i : mProximityAlerts.values()) { 2029 if (i.mUid == uid) { 2030 if (queryRestart) { 2031 setResultCode(Activity.RESULT_OK); 2032 return; 2033 } 2034 if (removedAlerts == null) { 2035 removedAlerts = new ArrayList<ProximityAlert>(); 2036 } 2037 if (!removedAlerts.contains(i)) { 2038 removedAlerts.add(i); 2039 } 2040 } 2041 } 2042 if (removedRecs != null) { 2043 for (int i=removedRecs.size()-1; i>=0; i--) { 2044 removeUpdatesLocked(removedRecs.get(i)); 2045 } 2046 } 2047 if (removedAlerts != null) { 2048 for (int i=removedAlerts.size()-1; i>=0; i--) { 2049 removeProximityAlertLocked(removedAlerts.get(i).mIntent); 2050 } 2051 } 2052 } 2053 } 2054 } 2055 } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 2056 boolean noConnectivity = 2057 intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); 2058 if (!noConnectivity) { 2059 mNetworkState = LocationProvider.AVAILABLE; 2060 } else { 2061 mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE; 2062 } 2063 2064 final ConnectivityManager connManager = (ConnectivityManager) context 2065 .getSystemService(Context.CONNECTIVITY_SERVICE); 2066 final NetworkInfo info = connManager.getActiveNetworkInfo(); 2067 2068 // Notify location providers of current network state 2069 synchronized (mLock) { 2070 for (int i = mProviders.size() - 1; i >= 0; i--) { 2071 LocationProviderInterface provider = mProviders.get(i); 2072 if (provider.requiresNetwork()) { 2073 provider.updateNetworkState(mNetworkState, info); 2074 } 2075 } 2076 } 2077 } 2078 } 2079 }; 2080 2081 private final PackageMonitor mPackageMonitor = new PackageMonitor() { 2082 @Override 2083 public void onPackageUpdateFinished(String packageName, int uid) { 2084 // Called by main thread; divert work to LocationWorker. 2085 Message.obtain(mLocationHandler, MESSAGE_PACKAGE_UPDATED, packageName).sendToTarget(); 2086 } 2087 @Override 2088 public void onPackageAdded(String packageName, int uid) { 2089 // Called by main thread; divert work to LocationWorker. 2090 Message.obtain(mLocationHandler, MESSAGE_PACKAGE_UPDATED, packageName).sendToTarget(); 2091 } 2092 }; 2093 2094 // Wake locks 2095 2096 private void incrementPendingBroadcasts() { 2097 synchronized (mWakeLock) { 2098 if (mPendingBroadcasts++ == 0) { 2099 try { 2100 mWakeLock.acquire(); 2101 log("Acquired wakelock"); 2102 } catch (Exception e) { 2103 // This is to catch a runtime exception thrown when we try to release an 2104 // already released lock. 2105 Slog.e(TAG, "exception in acquireWakeLock()", e); 2106 } 2107 } 2108 } 2109 } 2110 2111 private void decrementPendingBroadcasts() { 2112 synchronized (mWakeLock) { 2113 if (--mPendingBroadcasts == 0) { 2114 try { 2115 // Release wake lock 2116 if (mWakeLock.isHeld()) { 2117 mWakeLock.release(); 2118 log("Released wakelock"); 2119 } else { 2120 log("Can't release wakelock again!"); 2121 } 2122 } catch (Exception e) { 2123 // This is to catch a runtime exception thrown when we try to release an 2124 // already released lock. 2125 Slog.e(TAG, "exception in releaseWakeLock()", e); 2126 } 2127 } 2128 } 2129 } 2130 2131 // Geocoder 2132 2133 public boolean geocoderIsPresent() { 2134 return mGeocodeProvider != null; 2135 } 2136 2137 public String getFromLocation(double latitude, double longitude, int maxResults, 2138 GeocoderParams params, List<Address> addrs) { 2139 if (mGeocodeProvider != null) { 2140 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, 2141 params, addrs); 2142 } 2143 return null; 2144 } 2145 2146 2147 public String getFromLocationName(String locationName, 2148 double lowerLeftLatitude, double lowerLeftLongitude, 2149 double upperRightLatitude, double upperRightLongitude, int maxResults, 2150 GeocoderParams params, List<Address> addrs) { 2151 2152 if (mGeocodeProvider != null) { 2153 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude, 2154 lowerLeftLongitude, upperRightLatitude, upperRightLongitude, 2155 maxResults, params, addrs); 2156 } 2157 return null; 2158 } 2159 2160 // Mock Providers 2161 2162 private void checkMockPermissionsSafe() { 2163 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(), 2164 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1; 2165 if (!allowMocks) { 2166 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting"); 2167 } 2168 2169 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) != 2170 PackageManager.PERMISSION_GRANTED) { 2171 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission"); 2172 } 2173 } 2174 2175 public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite, 2176 boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, 2177 boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) { 2178 checkMockPermissionsSafe(); 2179 2180 if (LocationManager.PASSIVE_PROVIDER.equals(name)) { 2181 throw new IllegalArgumentException("Cannot mock the passive location provider"); 2182 } 2183 2184 long identity = Binder.clearCallingIdentity(); 2185 synchronized (mLock) { 2186 MockProvider provider = new MockProvider(name, this, 2187 requiresNetwork, requiresSatellite, 2188 requiresCell, hasMonetaryCost, supportsAltitude, 2189 supportsSpeed, supportsBearing, powerRequirement, accuracy); 2190 // remove the real provider if we are replacing GPS or network provider 2191 if (LocationManager.GPS_PROVIDER.equals(name) 2192 || LocationManager.NETWORK_PROVIDER.equals(name)) { 2193 LocationProviderInterface p = mProvidersByName.get(name); 2194 if (p != null) { 2195 p.enableLocationTracking(false); 2196 removeProvider(p); 2197 } 2198 } 2199 if (mProvidersByName.get(name) != null) { 2200 throw new IllegalArgumentException("Provider \"" + name + "\" already exists"); 2201 } 2202 addProvider(provider); 2203 mMockProviders.put(name, provider); 2204 mLastKnownLocation.put(name, null); 2205 updateProvidersLocked(); 2206 } 2207 Binder.restoreCallingIdentity(identity); 2208 } 2209 2210 public void removeTestProvider(String provider) { 2211 checkMockPermissionsSafe(); 2212 synchronized (mLock) { 2213 MockProvider mockProvider = mMockProviders.get(provider); 2214 if (mockProvider == null) { 2215 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2216 } 2217 long identity = Binder.clearCallingIdentity(); 2218 removeProvider(mProvidersByName.get(provider)); 2219 mMockProviders.remove(mockProvider); 2220 // reinstall real provider if we were mocking GPS or network provider 2221 if (LocationManager.GPS_PROVIDER.equals(provider) && 2222 mGpsLocationProvider != null) { 2223 addProvider(mGpsLocationProvider); 2224 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) && 2225 mNetworkLocationProvider != null) { 2226 addProvider(mNetworkLocationProvider); 2227 } 2228 mLastKnownLocation.put(provider, null); 2229 updateProvidersLocked(); 2230 Binder.restoreCallingIdentity(identity); 2231 } 2232 } 2233 2234 public void setTestProviderLocation(String provider, Location loc) { 2235 checkMockPermissionsSafe(); 2236 synchronized (mLock) { 2237 MockProvider mockProvider = mMockProviders.get(provider); 2238 if (mockProvider == null) { 2239 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2240 } 2241 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required 2242 long identity = Binder.clearCallingIdentity(); 2243 mockProvider.setLocation(loc); 2244 Binder.restoreCallingIdentity(identity); 2245 } 2246 } 2247 2248 public void clearTestProviderLocation(String provider) { 2249 checkMockPermissionsSafe(); 2250 synchronized (mLock) { 2251 MockProvider mockProvider = mMockProviders.get(provider); 2252 if (mockProvider == null) { 2253 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2254 } 2255 mockProvider.clearLocation(); 2256 } 2257 } 2258 2259 public void setTestProviderEnabled(String provider, boolean enabled) { 2260 checkMockPermissionsSafe(); 2261 synchronized (mLock) { 2262 MockProvider mockProvider = mMockProviders.get(provider); 2263 if (mockProvider == null) { 2264 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2265 } 2266 long identity = Binder.clearCallingIdentity(); 2267 if (enabled) { 2268 mockProvider.enable(); 2269 mEnabledProviders.add(provider); 2270 mDisabledProviders.remove(provider); 2271 } else { 2272 mockProvider.disable(); 2273 mEnabledProviders.remove(provider); 2274 mDisabledProviders.add(provider); 2275 } 2276 updateProvidersLocked(); 2277 Binder.restoreCallingIdentity(identity); 2278 } 2279 } 2280 2281 public void clearTestProviderEnabled(String provider) { 2282 checkMockPermissionsSafe(); 2283 synchronized (mLock) { 2284 MockProvider mockProvider = mMockProviders.get(provider); 2285 if (mockProvider == null) { 2286 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2287 } 2288 long identity = Binder.clearCallingIdentity(); 2289 mEnabledProviders.remove(provider); 2290 mDisabledProviders.remove(provider); 2291 updateProvidersLocked(); 2292 Binder.restoreCallingIdentity(identity); 2293 } 2294 } 2295 2296 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) { 2297 checkMockPermissionsSafe(); 2298 synchronized (mLock) { 2299 MockProvider mockProvider = mMockProviders.get(provider); 2300 if (mockProvider == null) { 2301 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2302 } 2303 mockProvider.setStatus(status, extras, updateTime); 2304 } 2305 } 2306 2307 public void clearTestProviderStatus(String provider) { 2308 checkMockPermissionsSafe(); 2309 synchronized (mLock) { 2310 MockProvider mockProvider = mMockProviders.get(provider); 2311 if (mockProvider == null) { 2312 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2313 } 2314 mockProvider.clearStatus(); 2315 } 2316 } 2317 2318 private void log(String log) { 2319 if (Log.isLoggable(TAG, Log.VERBOSE)) { 2320 Slog.d(TAG, log); 2321 } 2322 } 2323 2324 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2325 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 2326 != PackageManager.PERMISSION_GRANTED) { 2327 pw.println("Permission Denial: can't dump LocationManagerService from from pid=" 2328 + Binder.getCallingPid() 2329 + ", uid=" + Binder.getCallingUid()); 2330 return; 2331 } 2332 2333 synchronized (mLock) { 2334 pw.println("Current Location Manager state:"); 2335 pw.println(" sProvidersLoaded=" + sProvidersLoaded); 2336 pw.println(" Listeners:"); 2337 int N = mReceivers.size(); 2338 for (int i=0; i<N; i++) { 2339 pw.println(" " + mReceivers.get(i)); 2340 } 2341 pw.println(" Location Listeners:"); 2342 for (Receiver i : mReceivers.values()) { 2343 pw.println(" " + i + ":"); 2344 for (Map.Entry<String,UpdateRecord> j : i.mUpdateRecords.entrySet()) { 2345 pw.println(" " + j.getKey() + ":"); 2346 j.getValue().dump(pw, " "); 2347 } 2348 } 2349 pw.println(" Records by Provider:"); 2350 for (Map.Entry<String, ArrayList<UpdateRecord>> i 2351 : mRecordsByProvider.entrySet()) { 2352 pw.println(" " + i.getKey() + ":"); 2353 for (UpdateRecord j : i.getValue()) { 2354 pw.println(" " + j + ":"); 2355 j.dump(pw, " "); 2356 } 2357 } 2358 pw.println(" Last Known Locations:"); 2359 for (Map.Entry<String, Location> i 2360 : mLastKnownLocation.entrySet()) { 2361 pw.println(" " + i.getKey() + ":"); 2362 i.getValue().dump(new PrintWriterPrinter(pw), " "); 2363 } 2364 if (mProximityAlerts.size() > 0) { 2365 pw.println(" Proximity Alerts:"); 2366 for (Map.Entry<PendingIntent, ProximityAlert> i 2367 : mProximityAlerts.entrySet()) { 2368 pw.println(" " + i.getKey() + ":"); 2369 i.getValue().dump(pw, " "); 2370 } 2371 } 2372 if (mProximitiesEntered.size() > 0) { 2373 pw.println(" Proximities Entered:"); 2374 for (ProximityAlert i : mProximitiesEntered) { 2375 pw.println(" " + i + ":"); 2376 i.dump(pw, " "); 2377 } 2378 } 2379 pw.println(" mProximityReceiver=" + mProximityReceiver); 2380 pw.println(" mProximityListener=" + mProximityListener); 2381 if (mEnabledProviders.size() > 0) { 2382 pw.println(" Enabled Providers:"); 2383 for (String i : mEnabledProviders) { 2384 pw.println(" " + i); 2385 } 2386 2387 } 2388 if (mDisabledProviders.size() > 0) { 2389 pw.println(" Disabled Providers:"); 2390 for (String i : mDisabledProviders) { 2391 pw.println(" " + i); 2392 } 2393 2394 } 2395 if (mMockProviders.size() > 0) { 2396 pw.println(" Mock Providers:"); 2397 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) { 2398 i.getValue().dump(pw, " "); 2399 } 2400 } 2401 for (LocationProviderInterface provider: mProviders) { 2402 String state = provider.getInternalState(); 2403 if (state != null) { 2404 pw.println(provider.getName() + " Internal State:"); 2405 pw.write(state); 2406 } 2407 } 2408 } 2409 } 2410} 2411