LocationManagerService.java revision 2eeeec248a38ff33999c83f4b8d5bab7d50e79d2
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 ConnectivityManager connManager = (ConnectivityManager) context 1808 .getSystemService(Context.CONNECTIVITY_SERVICE); 1809 final NetworkInfo info = connManager.getActiveNetworkInfo(); 1810 1811 // Notify location providers of current network state 1812 synchronized (mLock) { 1813 for (int i = mProviders.size() - 1; i >= 0; i--) { 1814 LocationProviderInterface provider = mProviders.get(i); 1815 if (provider.requiresNetwork()) { 1816 provider.updateNetworkState(mNetworkState, info); 1817 } 1818 } 1819 } 1820 } 1821 } 1822 }; 1823 1824 private final PackageMonitor mPackageMonitor = new PackageMonitor() { 1825 @Override 1826 public void onPackageUpdateFinished(String packageName, int uid) { 1827 // Called by main thread; divert work to LocationWorker. 1828 Message.obtain(mLocationHandler, MESSAGE_PACKAGE_UPDATED, packageName).sendToTarget(); 1829 } 1830 @Override 1831 public void onPackageAdded(String packageName, int uid) { 1832 // Called by main thread; divert work to LocationWorker. 1833 Message.obtain(mLocationHandler, MESSAGE_PACKAGE_UPDATED, packageName).sendToTarget(); 1834 } 1835 @Override 1836 public void onPackageDisappeared(String packageName, int uid) { 1837 mGeofenceManager.removeFence(packageName); 1838 } 1839 }; 1840 1841 // Wake locks 1842 1843 private void incrementPendingBroadcasts() { 1844 synchronized (mWakeLock) { 1845 if (mPendingBroadcasts++ == 0) { 1846 try { 1847 mWakeLock.acquire(); 1848 log("Acquired wakelock"); 1849 } catch (Exception e) { 1850 // This is to catch a runtime exception thrown when we try to release an 1851 // already released lock. 1852 Slog.e(TAG, "exception in acquireWakeLock()", e); 1853 } 1854 } 1855 } 1856 } 1857 1858 private void decrementPendingBroadcasts() { 1859 synchronized (mWakeLock) { 1860 if (--mPendingBroadcasts == 0) { 1861 try { 1862 // Release wake lock 1863 if (mWakeLock.isHeld()) { 1864 mWakeLock.release(); 1865 log("Released wakelock"); 1866 } else { 1867 log("Can't release wakelock again!"); 1868 } 1869 } catch (Exception e) { 1870 // This is to catch a runtime exception thrown when we try to release an 1871 // already released lock. 1872 Slog.e(TAG, "exception in releaseWakeLock()", e); 1873 } 1874 } 1875 } 1876 } 1877 1878 // Geocoder 1879 1880 @Override 1881 public boolean geocoderIsPresent() { 1882 return mGeocodeProvider != null; 1883 } 1884 1885 @Override 1886 public String getFromLocation(double latitude, double longitude, int maxResults, 1887 GeocoderParams params, List<Address> addrs) { 1888 if (mGeocodeProvider != null) { 1889 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, 1890 params, addrs); 1891 } 1892 return null; 1893 } 1894 1895 1896 @Override 1897 public String getFromLocationName(String locationName, 1898 double lowerLeftLatitude, double lowerLeftLongitude, 1899 double upperRightLatitude, double upperRightLongitude, int maxResults, 1900 GeocoderParams params, List<Address> addrs) { 1901 1902 if (mGeocodeProvider != null) { 1903 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude, 1904 lowerLeftLongitude, upperRightLatitude, upperRightLongitude, 1905 maxResults, params, addrs); 1906 } 1907 return null; 1908 } 1909 1910 // Mock Providers 1911 1912 private void checkMockPermissionsSafe() { 1913 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(), 1914 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1; 1915 if (!allowMocks) { 1916 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting"); 1917 } 1918 1919 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) != 1920 PackageManager.PERMISSION_GRANTED) { 1921 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission"); 1922 } 1923 } 1924 1925 @Override 1926 public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite, 1927 boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, 1928 boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) { 1929 checkMockPermissionsSafe(); 1930 1931 if (LocationManager.PASSIVE_PROVIDER.equals(name)) { 1932 throw new IllegalArgumentException("Cannot mock the passive location provider"); 1933 } 1934 1935 long identity = Binder.clearCallingIdentity(); 1936 synchronized (mLock) { 1937 MockProvider provider = new MockProvider(name, this, 1938 requiresNetwork, requiresSatellite, 1939 requiresCell, hasMonetaryCost, supportsAltitude, 1940 supportsSpeed, supportsBearing, powerRequirement, accuracy); 1941 // remove the real provider if we are replacing GPS or network provider 1942 if (LocationManager.GPS_PROVIDER.equals(name) 1943 || LocationManager.NETWORK_PROVIDER.equals(name)) { 1944 LocationProviderInterface p = mProvidersByName.get(name); 1945 if (p != null) { 1946 p.enableLocationTracking(false); 1947 removeProvider(p); 1948 } 1949 } 1950 if (mProvidersByName.get(name) != null) { 1951 throw new IllegalArgumentException("Provider \"" + name + "\" already exists"); 1952 } 1953 addProvider(provider); 1954 mMockProviders.put(name, provider); 1955 mLastKnownLocation.put(name, null); 1956 updateProvidersLocked(); 1957 } 1958 Binder.restoreCallingIdentity(identity); 1959 } 1960 1961 @Override 1962 public void removeTestProvider(String provider) { 1963 checkMockPermissionsSafe(); 1964 synchronized (mLock) { 1965 MockProvider mockProvider = mMockProviders.get(provider); 1966 if (mockProvider == null) { 1967 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1968 } 1969 long identity = Binder.clearCallingIdentity(); 1970 removeProvider(mProvidersByName.get(provider)); 1971 mMockProviders.remove(mockProvider); 1972 // reinstall real provider if we were mocking GPS or network provider 1973 if (LocationManager.GPS_PROVIDER.equals(provider) && 1974 mGpsLocationProvider != null) { 1975 addProvider(mGpsLocationProvider); 1976 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) && 1977 mNetworkLocationProvider != null) { 1978 addProvider(mNetworkLocationProvider); 1979 } 1980 mLastKnownLocation.put(provider, null); 1981 updateProvidersLocked(); 1982 Binder.restoreCallingIdentity(identity); 1983 } 1984 } 1985 1986 @Override 1987 public void setTestProviderLocation(String provider, Location loc) { 1988 checkMockPermissionsSafe(); 1989 synchronized (mLock) { 1990 MockProvider mockProvider = mMockProviders.get(provider); 1991 if (mockProvider == null) { 1992 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1993 } 1994 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required 1995 long identity = Binder.clearCallingIdentity(); 1996 mockProvider.setLocation(loc); 1997 Binder.restoreCallingIdentity(identity); 1998 } 1999 } 2000 2001 @Override 2002 public void clearTestProviderLocation(String provider) { 2003 checkMockPermissionsSafe(); 2004 synchronized (mLock) { 2005 MockProvider mockProvider = mMockProviders.get(provider); 2006 if (mockProvider == null) { 2007 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2008 } 2009 mockProvider.clearLocation(); 2010 } 2011 } 2012 2013 @Override 2014 public void setTestProviderEnabled(String provider, boolean enabled) { 2015 checkMockPermissionsSafe(); 2016 synchronized (mLock) { 2017 MockProvider mockProvider = mMockProviders.get(provider); 2018 if (mockProvider == null) { 2019 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2020 } 2021 long identity = Binder.clearCallingIdentity(); 2022 if (enabled) { 2023 mockProvider.enable(); 2024 mEnabledProviders.add(provider); 2025 mDisabledProviders.remove(provider); 2026 } else { 2027 mockProvider.disable(); 2028 mEnabledProviders.remove(provider); 2029 mDisabledProviders.add(provider); 2030 } 2031 updateProvidersLocked(); 2032 Binder.restoreCallingIdentity(identity); 2033 } 2034 } 2035 2036 @Override 2037 public void clearTestProviderEnabled(String provider) { 2038 checkMockPermissionsSafe(); 2039 synchronized (mLock) { 2040 MockProvider mockProvider = mMockProviders.get(provider); 2041 if (mockProvider == null) { 2042 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2043 } 2044 long identity = Binder.clearCallingIdentity(); 2045 mEnabledProviders.remove(provider); 2046 mDisabledProviders.remove(provider); 2047 updateProvidersLocked(); 2048 Binder.restoreCallingIdentity(identity); 2049 } 2050 } 2051 2052 @Override 2053 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) { 2054 checkMockPermissionsSafe(); 2055 synchronized (mLock) { 2056 MockProvider mockProvider = mMockProviders.get(provider); 2057 if (mockProvider == null) { 2058 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2059 } 2060 mockProvider.setStatus(status, extras, updateTime); 2061 } 2062 } 2063 2064 @Override 2065 public void clearTestProviderStatus(String provider) { 2066 checkMockPermissionsSafe(); 2067 synchronized (mLock) { 2068 MockProvider mockProvider = mMockProviders.get(provider); 2069 if (mockProvider == null) { 2070 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2071 } 2072 mockProvider.clearStatus(); 2073 } 2074 } 2075 2076 private void log(String log) { 2077 if (Log.isLoggable(TAG, Log.VERBOSE)) { 2078 Slog.d(TAG, log); 2079 } 2080 } 2081 2082 @Override 2083 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2084 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 2085 != PackageManager.PERMISSION_GRANTED) { 2086 pw.println("Permission Denial: can't dump LocationManagerService from from pid=" 2087 + Binder.getCallingPid() 2088 + ", uid=" + Binder.getCallingUid()); 2089 return; 2090 } 2091 2092 synchronized (mLock) { 2093 pw.println("Current Location Manager state:"); 2094 pw.println(" sProvidersLoaded=" + sProvidersLoaded); 2095 pw.println(" Listeners:"); 2096 int N = mReceivers.size(); 2097 for (int i=0; i<N; i++) { 2098 pw.println(" " + mReceivers.get(i)); 2099 } 2100 pw.println(" Location Listeners:"); 2101 for (Receiver i : mReceivers.values()) { 2102 pw.println(" " + i + ":"); 2103 for (Map.Entry<String,UpdateRecord> j : i.mUpdateRecords.entrySet()) { 2104 pw.println(" " + j.getKey() + ":"); 2105 j.getValue().dump(pw, " "); 2106 } 2107 } 2108 pw.println(" Records by Provider:"); 2109 for (Map.Entry<String, ArrayList<UpdateRecord>> i 2110 : mRecordsByProvider.entrySet()) { 2111 pw.println(" " + i.getKey() + ":"); 2112 for (UpdateRecord j : i.getValue()) { 2113 pw.println(" " + j + ":"); 2114 j.dump(pw, " "); 2115 } 2116 } 2117 pw.println(" Last Known Locations:"); 2118 for (Map.Entry<String, Location> i 2119 : mLastKnownLocation.entrySet()) { 2120 pw.println(" " + i.getKey() + ":"); 2121 i.getValue().dump(new PrintWriterPrinter(pw), " "); 2122 } 2123 mGeofenceManager.dump(pw); 2124 if (mEnabledProviders.size() > 0) { 2125 pw.println(" Enabled Providers:"); 2126 for (String i : mEnabledProviders) { 2127 pw.println(" " + i); 2128 } 2129 2130 } 2131 if (mDisabledProviders.size() > 0) { 2132 pw.println(" Disabled Providers:"); 2133 for (String i : mDisabledProviders) { 2134 pw.println(" " + i); 2135 } 2136 2137 } 2138 if (mMockProviders.size() > 0) { 2139 pw.println(" Mock Providers:"); 2140 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) { 2141 i.getValue().dump(pw, " "); 2142 } 2143 } 2144 for (LocationProviderInterface provider: mProviders) { 2145 String state = provider.getInternalState(); 2146 if (state != null) { 2147 pw.println(provider.getName() + " Internal State:"); 2148 pw.write(state); 2149 } 2150 } 2151 } 2152 } 2153} 2154