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