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