LocationManagerService.java revision 595dda6d47a4eeeffc32abbfbc55edfba588d846
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.PendingIntent; 20import android.content.ContentQueryMap; 21import android.content.ContentResolver; 22import android.content.Context; 23import android.content.Intent; 24import android.content.IntentFilter; 25import android.content.pm.ApplicationInfo; 26import android.content.pm.PackageManager; 27import android.content.pm.PackageManager.NameNotFoundException; 28import android.content.res.Resources; 29import android.database.Cursor; 30import android.location.Address; 31import android.location.Criteria; 32import android.location.GeocoderParams; 33import android.location.Geofence; 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.location.LocationRequest; 43import android.net.ConnectivityManager; 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.SystemClock; 54import android.os.WorkSource; 55import android.provider.Settings; 56import android.provider.Settings.NameValueTable; 57import android.util.Log; 58import android.util.Slog; 59 60import com.android.internal.content.PackageMonitor; 61import com.android.internal.location.ProviderProperties; 62import com.android.internal.location.ProviderRequest; 63import com.android.server.location.GeocoderProxy; 64import com.android.server.location.GeofenceManager; 65import com.android.server.location.GpsLocationProvider; 66import com.android.server.location.LocationBlacklist; 67import com.android.server.location.LocationFudger; 68import com.android.server.location.LocationProviderInterface; 69import com.android.server.location.LocationProviderProxy; 70import com.android.server.location.MockProvider; 71import com.android.server.location.PassiveProvider; 72 73import java.io.FileDescriptor; 74import java.io.PrintWriter; 75import java.util.ArrayList; 76import java.util.Arrays; 77import java.util.HashMap; 78import java.util.HashSet; 79import java.util.List; 80import java.util.Map; 81import java.util.Observable; 82import java.util.Observer; 83import java.util.Set; 84 85/** 86 * The service class that manages LocationProviders and issues location 87 * updates and alerts. 88 */ 89public class LocationManagerService extends ILocationManager.Stub implements Observer, Runnable { 90 private static final String TAG = "LocationManagerService"; 91 public static final boolean D = false; 92 93 private static final String WAKELOCK_KEY = TAG; 94 private static final String THREAD_NAME = TAG; 95 96 private static final String ACCESS_FINE_LOCATION = 97 android.Manifest.permission.ACCESS_FINE_LOCATION; 98 private static final String ACCESS_COARSE_LOCATION = 99 android.Manifest.permission.ACCESS_COARSE_LOCATION; 100 private static final String ACCESS_MOCK_LOCATION = 101 android.Manifest.permission.ACCESS_MOCK_LOCATION; 102 private static final String ACCESS_LOCATION_EXTRA_COMMANDS = 103 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS; 104 private static final String INSTALL_LOCATION_PROVIDER = 105 android.Manifest.permission.INSTALL_LOCATION_PROVIDER; 106 107 private static final String NETWORK_LOCATION_SERVICE_ACTION = 108 "com.android.location.service.v2.NetworkLocationProvider"; 109 private static final String FUSED_LOCATION_SERVICE_ACTION = 110 "com.android.location.service.FusedLocationProvider"; 111 112 private static final int MSG_LOCATION_CHANGED = 1; 113 114 // Location Providers may sometimes deliver location updates 115 // slightly faster that requested - provide grace period so 116 // we don't unnecessarily filter events that are otherwise on 117 // time 118 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100; 119 120 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest(); 121 122 private final Context mContext; 123 124 // used internally for synchronization 125 private final Object mLock = new Object(); 126 127 // --- fields below are final after init() --- 128 private LocationFudger mLocationFudger; 129 private GeofenceManager mGeofenceManager; 130 private PowerManager.WakeLock mWakeLock; 131 private PackageManager mPackageManager; 132 private GeocoderProxy mGeocodeProvider; 133 private IGpsStatusProvider mGpsStatusProvider; 134 private INetInitiatedListener mNetInitiatedListener; 135 private LocationWorkerHandler mLocationHandler; 136 private PassiveProvider mPassiveProvider; // track passive provider for special cases 137 private LocationBlacklist mBlacklist; 138 139 // --- fields below are protected by mWakeLock --- 140 private int mPendingBroadcasts; 141 142 // --- fields below are protected by mLock --- 143 // Set of providers that are explicitly enabled 144 private final Set<String> mEnabledProviders = new HashSet<String>(); 145 146 // Set of providers that are explicitly disabled 147 private final Set<String> mDisabledProviders = new HashSet<String>(); 148 149 // Mock (test) providers 150 private final HashMap<String, MockProvider> mMockProviders = 151 new HashMap<String, MockProvider>(); 152 153 // all receivers 154 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>(); 155 156 // currently installed providers (with mocks replacing real providers) 157 private final ArrayList<LocationProviderInterface> mProviders = 158 new ArrayList<LocationProviderInterface>(); 159 160 // real providers, saved here when mocked out 161 private final HashMap<String, LocationProviderInterface> mRealProviders = 162 new HashMap<String, LocationProviderInterface>(); 163 164 // mapping from provider name to provider 165 private final HashMap<String, LocationProviderInterface> mProvidersByName = 166 new HashMap<String, LocationProviderInterface>(); 167 168 // mapping from provider name to all its UpdateRecords 169 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider = 170 new HashMap<String, ArrayList<UpdateRecord>>(); 171 172 // mapping from provider name to last known location 173 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>(); 174 175 // all providers that operate over proxy, for authorizing incoming location 176 private final ArrayList<LocationProviderProxy> mProxyProviders = 177 new ArrayList<LocationProviderProxy>(); 178 179 public LocationManagerService(Context context) { 180 super(); 181 mContext = context; 182 183 if (D) Log.d(TAG, "Constructed"); 184 185 // most startup is deferred until systemReady() 186 } 187 188 public void systemReady() { 189 Thread thread = new Thread(null, this, THREAD_NAME); 190 thread.start(); 191 } 192 193 @Override 194 public void run() { 195 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 196 Looper.prepare(); 197 mLocationHandler = new LocationWorkerHandler(); 198 init(); 199 Looper.loop(); 200 } 201 202 private void init() { 203 if (D) Log.d(TAG, "init()"); 204 205 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 206 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); 207 mPackageManager = mContext.getPackageManager(); 208 209 synchronized (mLock) { 210 loadProvidersLocked(); 211 } 212 mBlacklist = new LocationBlacklist(mContext, mLocationHandler); 213 mBlacklist.init(); 214 mGeofenceManager = new GeofenceManager(mContext, mBlacklist); 215 mLocationFudger = new LocationFudger(); 216 217 // listen for settings changes 218 ContentResolver resolver = mContext.getContentResolver(); 219 Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null, 220 "(" + NameValueTable.NAME + "=?)", 221 new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED}, null); 222 ContentQueryMap query = new ContentQueryMap(settingsCursor, NameValueTable.NAME, true, 223 mLocationHandler); 224 settingsCursor.close(); 225 query.addObserver(this); 226 mPackageMonitor.register(mContext, Looper.myLooper(), true); 227 } 228 229 private void loadProvidersLocked() { 230 if (GpsLocationProvider.isSupported()) { 231 // Create a gps location provider 232 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this); 233 mGpsStatusProvider = gpsProvider.getGpsStatusProvider(); 234 mNetInitiatedListener = gpsProvider.getNetInitiatedListener(); 235 addProviderLocked(gpsProvider); 236 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider); 237 } 238 239 // create a passive location provider, which is always enabled 240 PassiveProvider passiveProvider = new PassiveProvider(this); 241 addProviderLocked(passiveProvider); 242 mEnabledProviders.add(passiveProvider.getName()); 243 mPassiveProvider = passiveProvider; 244 245 /* 246 Load package name(s) containing location provider support. 247 These packages can contain services implementing location providers: 248 Geocoder Provider, Network Location Provider, and 249 Fused Location Provider. They will each be searched for 250 service components implementing these providers. 251 The location framework also has support for installation 252 of new location providers at run-time. The new package does not 253 have to be explicitly listed here, however it must have a signature 254 that matches the signature of at least one package on this list. 255 */ 256 Resources resources = mContext.getResources(); 257 ArrayList<String> providerPackageNames = new ArrayList<String>(); 258 String[] pkgs1 = resources.getStringArray( 259 com.android.internal.R.array.config_locationProviderPackageNames); 260 String[] pkgs2 = resources.getStringArray( 261 com.android.internal.R.array.config_overlay_locationProviderPackageNames); 262 if (D) Log.d(TAG, "built-in location providers: " + Arrays.toString(pkgs1)); 263 if (D) Log.d(TAG, "overlay location providers: " + Arrays.toString(pkgs2)); 264 if (pkgs1 != null) providerPackageNames.addAll(Arrays.asList(pkgs1)); 265 if (pkgs2 != null) providerPackageNames.addAll(Arrays.asList(pkgs2)); 266 267 // bind to network provider 268 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind( 269 mContext, 270 LocationManager.NETWORK_PROVIDER, 271 NETWORK_LOCATION_SERVICE_ACTION, 272 providerPackageNames, mLocationHandler); 273 if (networkProvider != null) { 274 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider); 275 mProxyProviders.add(networkProvider); 276 addProviderLocked(networkProvider); 277 } else { 278 Slog.w(TAG, "no network location provider found"); 279 } 280 281 // bind to fused provider 282 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind( 283 mContext, 284 LocationManager.FUSED_PROVIDER, 285 FUSED_LOCATION_SERVICE_ACTION, 286 providerPackageNames, mLocationHandler); 287 if (fusedLocationProvider != null) { 288 addProviderLocked(fusedLocationProvider); 289 mProxyProviders.add(fusedLocationProvider); 290 mEnabledProviders.add(fusedLocationProvider.getName()); 291 } else { 292 Slog.e(TAG, "no fused location provider found", 293 new IllegalStateException("Location service needs a fused location provider")); 294 } 295 296 // bind to geocoder provider 297 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames); 298 if (mGeocodeProvider == null) { 299 Slog.e(TAG, "no geocoder provider found"); 300 } 301 302 updateProvidersLocked(); 303 } 304 305 /** 306 * A wrapper class holding either an ILocationListener or a PendingIntent to receive 307 * location updates. 308 */ 309 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished { 310 final int mUid; // uid of receiver 311 final int mPid; // pid of receiver 312 final String mPackageName; // package name of receiver 313 final String mPermission; // best permission that receiver has 314 315 final ILocationListener mListener; 316 final PendingIntent mPendingIntent; 317 final Object mKey; 318 319 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>(); 320 321 int mPendingBroadcasts; 322 323 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid, 324 String packageName) { 325 mListener = listener; 326 mPendingIntent = intent; 327 if (listener != null) { 328 mKey = listener.asBinder(); 329 } else { 330 mKey = intent; 331 } 332 mPermission = checkPermission(); 333 mUid = uid; 334 mPid = pid; 335 mPackageName = packageName; 336 } 337 338 @Override 339 public boolean equals(Object otherObj) { 340 if (otherObj instanceof Receiver) { 341 return mKey.equals(((Receiver)otherObj).mKey); 342 } 343 return false; 344 } 345 346 @Override 347 public int hashCode() { 348 return mKey.hashCode(); 349 } 350 351 @Override 352 public String toString() { 353 StringBuilder s = new StringBuilder(); 354 s.append("Reciever["); 355 s.append(Integer.toHexString(System.identityHashCode(this))); 356 if (mListener != null) { 357 s.append(" listener"); 358 } else { 359 s.append(" intent"); 360 } 361 for (String p : mUpdateRecords.keySet()) { 362 s.append(" ").append(mUpdateRecords.get(p).toString()); 363 } 364 s.append("]"); 365 return s.toString(); 366 } 367 368 public boolean isListener() { 369 return mListener != null; 370 } 371 372 public boolean isPendingIntent() { 373 return mPendingIntent != null; 374 } 375 376 public ILocationListener getListener() { 377 if (mListener != null) { 378 return mListener; 379 } 380 throw new IllegalStateException("Request for non-existent listener"); 381 } 382 383 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) { 384 if (mListener != null) { 385 try { 386 synchronized (this) { 387 // synchronize to ensure incrementPendingBroadcastsLocked() 388 // is called before decrementPendingBroadcasts() 389 mListener.onStatusChanged(provider, status, extras); 390 // call this after broadcasting so we do not increment 391 // if we throw an exeption. 392 incrementPendingBroadcastsLocked(); 393 } 394 } catch (RemoteException e) { 395 return false; 396 } 397 } else { 398 Intent statusChanged = new Intent(); 399 statusChanged.putExtras(extras); 400 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status); 401 try { 402 synchronized (this) { 403 // synchronize to ensure incrementPendingBroadcastsLocked() 404 // is called before decrementPendingBroadcasts() 405 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler, 406 mPermission); 407 // call this after broadcasting so we do not increment 408 // if we throw an exeption. 409 incrementPendingBroadcastsLocked(); 410 } 411 } catch (PendingIntent.CanceledException e) { 412 return false; 413 } 414 } 415 return true; 416 } 417 418 public boolean callLocationChangedLocked(Location location) { 419 if (mListener != null) { 420 try { 421 synchronized (this) { 422 // synchronize to ensure incrementPendingBroadcastsLocked() 423 // is called before decrementPendingBroadcasts() 424 mListener.onLocationChanged(location); 425 // call this after broadcasting so we do not increment 426 // if we throw an exeption. 427 incrementPendingBroadcastsLocked(); 428 } 429 } catch (RemoteException e) { 430 return false; 431 } 432 } else { 433 Intent locationChanged = new Intent(); 434 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location); 435 try { 436 synchronized (this) { 437 // synchronize to ensure incrementPendingBroadcastsLocked() 438 // is called before decrementPendingBroadcasts() 439 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler, 440 mPermission); 441 // call this after broadcasting so we do not increment 442 // if we throw an exeption. 443 incrementPendingBroadcastsLocked(); 444 } 445 } catch (PendingIntent.CanceledException e) { 446 return false; 447 } 448 } 449 return true; 450 } 451 452 public boolean callProviderEnabledLocked(String provider, boolean enabled) { 453 if (mListener != null) { 454 try { 455 synchronized (this) { 456 // synchronize to ensure incrementPendingBroadcastsLocked() 457 // is called before decrementPendingBroadcasts() 458 if (enabled) { 459 mListener.onProviderEnabled(provider); 460 } else { 461 mListener.onProviderDisabled(provider); 462 } 463 // call this after broadcasting so we do not increment 464 // if we throw an exeption. 465 incrementPendingBroadcastsLocked(); 466 } 467 } catch (RemoteException e) { 468 return false; 469 } 470 } else { 471 Intent providerIntent = new Intent(); 472 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled); 473 try { 474 synchronized (this) { 475 // synchronize to ensure incrementPendingBroadcastsLocked() 476 // is called before decrementPendingBroadcasts() 477 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler, 478 mPermission); 479 // call this after broadcasting so we do not increment 480 // if we throw an exeption. 481 incrementPendingBroadcastsLocked(); 482 } 483 } catch (PendingIntent.CanceledException e) { 484 return false; 485 } 486 } 487 return true; 488 } 489 490 @Override 491 public void binderDied() { 492 if (D) Log.d(TAG, "Location listener died"); 493 494 synchronized (mLock) { 495 removeUpdatesLocked(this); 496 } 497 synchronized (this) { 498 if (mPendingBroadcasts > 0) { 499 LocationManagerService.this.decrementPendingBroadcasts(); 500 mPendingBroadcasts = 0; 501 } 502 } 503 } 504 505 @Override 506 public void onSendFinished(PendingIntent pendingIntent, Intent intent, 507 int resultCode, String resultData, Bundle resultExtras) { 508 synchronized (this) { 509 decrementPendingBroadcastsLocked(); 510 } 511 } 512 513 // this must be called while synchronized by caller in a synchronized block 514 // containing the sending of the broadcaset 515 private void incrementPendingBroadcastsLocked() { 516 if (mPendingBroadcasts++ == 0) { 517 LocationManagerService.this.incrementPendingBroadcasts(); 518 } 519 } 520 521 private void decrementPendingBroadcastsLocked() { 522 if (--mPendingBroadcasts == 0) { 523 LocationManagerService.this.decrementPendingBroadcasts(); 524 } 525 } 526 } 527 528 @Override 529 public void locationCallbackFinished(ILocationListener listener) { 530 //Do not use getReceiver here as that will add the ILocationListener to 531 //the receiver list if it is not found. If it is not found then the 532 //LocationListener was removed when it had a pending broadcast and should 533 //not be added back. 534 IBinder binder = listener.asBinder(); 535 Receiver receiver = mReceivers.get(binder); 536 if (receiver != null) { 537 synchronized (receiver) { 538 // so wakelock calls will succeed 539 long identity = Binder.clearCallingIdentity(); 540 receiver.decrementPendingBroadcastsLocked(); 541 Binder.restoreCallingIdentity(identity); 542 } 543 } 544 } 545 546 /** Settings Observer callback */ 547 @Override 548 public void update(Observable o, Object arg) { 549 synchronized (mLock) { 550 updateProvidersLocked(); 551 } 552 } 553 554 private void addProviderLocked(LocationProviderInterface provider) { 555 mProviders.add(provider); 556 mProvidersByName.put(provider.getName(), provider); 557 } 558 559 private void removeProviderLocked(LocationProviderInterface provider) { 560 provider.disable(); 561 mProviders.remove(provider); 562 mProvidersByName.remove(provider.getName()); 563 } 564 565 566 private boolean isAllowedBySettingsLocked(String provider) { 567 if (mEnabledProviders.contains(provider)) { 568 return true; 569 } 570 if (mDisabledProviders.contains(provider)) { 571 return false; 572 } 573 // Use system settings 574 ContentResolver resolver = mContext.getContentResolver(); 575 576 return Settings.Secure.isLocationProviderEnabled(resolver, provider); 577 } 578 579 /** 580 * Throw SecurityException if caller has neither COARSE or FINE. 581 * Otherwise, return the best permission. 582 */ 583 private String checkPermission() { 584 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) == 585 PackageManager.PERMISSION_GRANTED) { 586 return ACCESS_FINE_LOCATION; 587 } else if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) == 588 PackageManager.PERMISSION_GRANTED) { 589 return ACCESS_COARSE_LOCATION; 590 } 591 592 throw new SecurityException("Location requires either ACCESS_COARSE_LOCATION or" + 593 "ACCESS_FINE_LOCATION permission"); 594 } 595 596 /** 597 * Returns all providers by name, including passive, but excluding 598 * fused. 599 */ 600 @Override 601 public List<String> getAllProviders() { 602 checkPermission(); 603 604 ArrayList<String> out; 605 synchronized (mLock) { 606 out = new ArrayList<String>(mProviders.size()); 607 for (LocationProviderInterface provider : mProviders) { 608 String name = provider.getName(); 609 if (LocationManager.FUSED_PROVIDER.equals(name)) { 610 continue; 611 } 612 out.add(name); 613 } 614 } 615 616 if (D) Log.d(TAG, "getAllProviders()=" + out); 617 return out; 618 } 619 620 /** 621 * Return all providers by name, that match criteria and are optionally 622 * enabled. 623 * Can return passive provider, but never returns fused provider. 624 */ 625 @Override 626 public List<String> getProviders(Criteria criteria, boolean enabledOnly) { 627 checkPermission(); 628 629 ArrayList<String> out; 630 synchronized (mLock) { 631 out = new ArrayList<String>(mProviders.size()); 632 for (LocationProviderInterface provider : mProviders) { 633 String name = provider.getName(); 634 if (LocationManager.FUSED_PROVIDER.equals(name)) { 635 continue; 636 } 637 if (enabledOnly && !isAllowedBySettingsLocked(name)) { 638 continue; 639 } 640 if (criteria != null && !LocationProvider.propertiesMeetCriteria( 641 name, provider.getProperties(), criteria)) { 642 continue; 643 } 644 out.add(name); 645 } 646 } 647 648 if (D) Log.d(TAG, "getProviders()=" + out); 649 return out; 650 } 651 652 /** 653 * Return the name of the best provider given a Criteria object. 654 * This method has been deprecated from the public API, 655 * and the whole LoactionProvider (including #meetsCriteria) 656 * has been deprecated as well. So this method now uses 657 * some simplified logic. 658 */ 659 @Override 660 public String getBestProvider(Criteria criteria, boolean enabledOnly) { 661 String result = null; 662 checkPermission(); 663 664 List<String> providers = getProviders(criteria, enabledOnly); 665 if (providers.size() < 1) { 666 result = pickBest(providers); 667 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result); 668 return result; 669 } 670 providers = getProviders(null, enabledOnly); 671 if (providers.size() >= 1) { 672 result = pickBest(providers); 673 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result); 674 return result; 675 } 676 677 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result); 678 return null; 679 } 680 681 private String pickBest(List<String> providers) { 682 if (providers.contains(LocationManager.NETWORK_PROVIDER)) { 683 return LocationManager.NETWORK_PROVIDER; 684 } else if (providers.contains(LocationManager.GPS_PROVIDER)) { 685 return LocationManager.GPS_PROVIDER; 686 } else { 687 return providers.get(0); 688 } 689 } 690 691 @Override 692 public boolean providerMeetsCriteria(String provider, Criteria criteria) { 693 checkPermission(); 694 695 LocationProviderInterface p = mProvidersByName.get(provider); 696 if (p == null) { 697 throw new IllegalArgumentException("provider=" + provider); 698 } 699 700 boolean result = LocationProvider.propertiesMeetCriteria( 701 p.getName(), p.getProperties(), criteria); 702 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result); 703 return result; 704 } 705 706 private void updateProvidersLocked() { 707 boolean changesMade = false; 708 for (int i = mProviders.size() - 1; i >= 0; i--) { 709 LocationProviderInterface p = mProviders.get(i); 710 boolean isEnabled = p.isEnabled(); 711 String name = p.getName(); 712 boolean shouldBeEnabled = isAllowedBySettingsLocked(name); 713 if (isEnabled && !shouldBeEnabled) { 714 updateProviderListenersLocked(name, false); 715 changesMade = true; 716 } else if (!isEnabled && shouldBeEnabled) { 717 updateProviderListenersLocked(name, true); 718 changesMade = true; 719 } 720 } 721 if (changesMade) { 722 mContext.sendBroadcast(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION)); 723 } 724 } 725 726 private void updateProviderListenersLocked(String provider, boolean enabled) { 727 int listeners = 0; 728 729 LocationProviderInterface p = mProvidersByName.get(provider); 730 if (p == null) return; 731 732 ArrayList<Receiver> deadReceivers = null; 733 734 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 735 if (records != null) { 736 final int N = records.size(); 737 for (int i = 0; i < N; i++) { 738 UpdateRecord record = records.get(i); 739 // Sends a notification message to the receiver 740 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) { 741 if (deadReceivers == null) { 742 deadReceivers = new ArrayList<Receiver>(); 743 } 744 deadReceivers.add(record.mReceiver); 745 } 746 listeners++; 747 } 748 } 749 750 if (deadReceivers != null) { 751 for (int i = deadReceivers.size() - 1; i >= 0; i--) { 752 removeUpdatesLocked(deadReceivers.get(i)); 753 } 754 } 755 756 if (enabled) { 757 p.enable(); 758 if (listeners > 0) { 759 applyRequirementsLocked(provider); 760 } 761 } else { 762 p.disable(); 763 } 764 } 765 766 private void applyRequirementsLocked(String provider) { 767 LocationProviderInterface p = mProvidersByName.get(provider); 768 if (p == null) return; 769 770 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 771 WorkSource worksource = new WorkSource(); 772 ProviderRequest providerRequest = new ProviderRequest(); 773 774 if (records != null) { 775 for (UpdateRecord record : records) { 776 LocationRequest locationRequest = record.mRequest; 777 778 providerRequest.locationRequests.add(locationRequest); 779 if (locationRequest.getInterval() < providerRequest.interval) { 780 providerRequest.reportLocation = true; 781 providerRequest.interval = locationRequest.getInterval(); 782 } 783 } 784 785 if (providerRequest.reportLocation) { 786 // calculate who to blame for power 787 // This is somewhat arbitrary. We pick a threshold interval 788 // that is slightly higher that the minimum interval, and 789 // spread the blame across all applications with a request 790 // under that threshold. 791 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2; 792 for (UpdateRecord record : records) { 793 LocationRequest locationRequest = record.mRequest; 794 if (locationRequest.getInterval() <= thresholdInterval) { 795 worksource.add(record.mReceiver.mUid); 796 } 797 } 798 } 799 } 800 801 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest); 802 p.setRequest(providerRequest, worksource); 803 } 804 805 private class UpdateRecord { 806 final String mProvider; 807 final LocationRequest mRequest; 808 final Receiver mReceiver; 809 Location mLastFixBroadcast; 810 long mLastStatusBroadcast; 811 812 /** 813 * Note: must be constructed with lock held. 814 */ 815 UpdateRecord(String provider, LocationRequest request, Receiver receiver) { 816 mProvider = provider; 817 mRequest = request; 818 mReceiver = receiver; 819 820 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 821 if (records == null) { 822 records = new ArrayList<UpdateRecord>(); 823 mRecordsByProvider.put(provider, records); 824 } 825 if (!records.contains(this)) { 826 records.add(this); 827 } 828 } 829 830 /** 831 * Method to be called when a record will no longer be used. Calling this multiple times 832 * must have the same effect as calling it once. 833 */ 834 void disposeLocked(boolean removeReceiver) { 835 // remove from mRecordsByProvider 836 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider); 837 if (globalRecords != null) { 838 globalRecords.remove(this); 839 } 840 841 if (!removeReceiver) return; // the caller will handle the rest 842 843 // remove from Receiver#mUpdateRecords 844 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords; 845 if (receiverRecords != null) { 846 receiverRecords.remove(this.mProvider); 847 848 // and also remove the Receiver if it has no more update records 849 if (removeReceiver && receiverRecords.size() == 0) { 850 removeUpdatesLocked(mReceiver); 851 } 852 } 853 } 854 855 @Override 856 public String toString() { 857 StringBuilder s = new StringBuilder(); 858 s.append("UpdateRecord["); 859 s.append(mProvider); 860 s.append(' ').append(mReceiver.mPackageName).append('('); 861 s.append(mReceiver.mUid).append(')'); 862 s.append(' ').append(mRequest); 863 s.append(']'); 864 return s.toString(); 865 } 866 } 867 868 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) { 869 IBinder binder = listener.asBinder(); 870 Receiver receiver = mReceivers.get(binder); 871 if (receiver == null) { 872 receiver = new Receiver(listener, null, pid, uid, packageName); 873 mReceivers.put(binder, receiver); 874 875 try { 876 receiver.getListener().asBinder().linkToDeath(receiver, 0); 877 } catch (RemoteException e) { 878 Slog.e(TAG, "linkToDeath failed:", e); 879 return null; 880 } 881 } 882 return receiver; 883 } 884 885 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) { 886 Receiver receiver = mReceivers.get(intent); 887 if (receiver == null) { 888 receiver = new Receiver(null, intent, pid, uid, packageName); 889 mReceivers.put(intent, receiver); 890 } 891 return receiver; 892 } 893 894 private String checkPermissionAndRequest(LocationRequest request) { 895 String perm = checkPermission(); 896 897 if (ACCESS_COARSE_LOCATION.equals(perm)) { 898 switch (request.getQuality()) { 899 case LocationRequest.ACCURACY_FINE: 900 request.setQuality(LocationRequest.ACCURACY_BLOCK); 901 break; 902 case LocationRequest.POWER_HIGH: 903 request.setQuality(LocationRequest.POWER_LOW); 904 break; 905 } 906 // throttle 907 if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) { 908 request.setInterval(LocationFudger.FASTEST_INTERVAL_MS); 909 } 910 if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) { 911 request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS); 912 } 913 } 914 // make getFastestInterval() the minimum of interval and fastest interval 915 if (request.getFastestInterval() > request.getInterval()) { 916 request.setFastestInterval(request.getInterval()); 917 } 918 return perm; 919 } 920 921 private void checkPackageName(String packageName) { 922 if (packageName == null) { 923 throw new SecurityException("invalid package name: " + packageName); 924 } 925 int uid = Binder.getCallingUid(); 926 String[] packages = mPackageManager.getPackagesForUid(uid); 927 if (packages == null) { 928 throw new SecurityException("invalid UID " + uid); 929 } 930 for (String pkg : packages) { 931 if (packageName.equals(pkg)) return; 932 } 933 throw new SecurityException("invalid package name: " + packageName); 934 } 935 936 private void checkPendingIntent(PendingIntent intent) { 937 if (intent == null) { 938 throw new IllegalArgumentException("invalid pending intent: " + intent); 939 } 940 } 941 942 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent, 943 int pid, int uid, String packageName) { 944 if (intent == null && listener == null) { 945 throw new IllegalArgumentException("need eiter listener or intent"); 946 } else if (intent != null && listener != null) { 947 throw new IllegalArgumentException("cannot register both listener and intent"); 948 } else if (intent != null) { 949 checkPendingIntent(intent); 950 return getReceiver(intent, pid, uid, packageName); 951 } else { 952 return getReceiver(listener, pid, uid, packageName); 953 } 954 } 955 956 @Override 957 public void requestLocationUpdates(LocationRequest request, ILocationListener listener, 958 PendingIntent intent, String packageName) { 959 if (request == null) request = DEFAULT_LOCATION_REQUEST; 960 checkPackageName(packageName); 961 checkPermissionAndRequest(request); 962 963 final int pid = Binder.getCallingPid(); 964 final int uid = Binder.getCallingUid(); 965 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName); 966 967 // providers may use public location API's, need to clear identity 968 long identity = Binder.clearCallingIdentity(); 969 try { 970 synchronized (mLock) { 971 requestLocationUpdatesLocked(request, recevier, pid, uid, packageName); 972 } 973 } finally { 974 Binder.restoreCallingIdentity(identity); 975 } 976 } 977 978 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver, 979 int pid, int uid, String packageName) { 980 // Figure out the provider. Either its explicitly request (legacy use cases), or 981 // use the fused provider 982 if (request == null) request = DEFAULT_LOCATION_REQUEST; 983 String name = request.getProvider(); 984 if (name == null) name = LocationManager.FUSED_PROVIDER; 985 LocationProviderInterface provider = mProvidersByName.get(name); 986 if (provider == null) { 987 throw new IllegalArgumentException("provider doesn't exisit: " + provider); 988 } 989 990 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " + 991 name + " " + request + " from " + packageName + "(" + uid + ")"); 992 993 UpdateRecord record = new UpdateRecord(name, request, receiver); 994 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record); 995 if (oldRecord != null) { 996 oldRecord.disposeLocked(false); 997 } 998 999 boolean isProviderEnabled = isAllowedBySettingsLocked(name); 1000 if (isProviderEnabled) { 1001 applyRequirementsLocked(name); 1002 } else { 1003 // Notify the listener that updates are currently disabled 1004 receiver.callProviderEnabledLocked(name, false); 1005 } 1006 } 1007 1008 @Override 1009 public void removeUpdates(ILocationListener listener, PendingIntent intent, 1010 String packageName) { 1011 checkPackageName(packageName); 1012 checkPermission(); 1013 final int pid = Binder.getCallingPid(); 1014 final int uid = Binder.getCallingUid(); 1015 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName); 1016 1017 // providers may use public location API's, need to clear identity 1018 long identity = Binder.clearCallingIdentity(); 1019 try { 1020 synchronized (mLock) { 1021 removeUpdatesLocked(receiver); 1022 } 1023 } finally { 1024 Binder.restoreCallingIdentity(identity); 1025 } 1026 } 1027 1028 private void removeUpdatesLocked(Receiver receiver) { 1029 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver))); 1030 1031 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) { 1032 receiver.getListener().asBinder().unlinkToDeath(receiver, 0); 1033 synchronized (receiver) { 1034 if (receiver.mPendingBroadcasts > 0) { 1035 decrementPendingBroadcasts(); 1036 receiver.mPendingBroadcasts = 0; 1037 } 1038 } 1039 } 1040 1041 // Record which providers were associated with this listener 1042 HashSet<String> providers = new HashSet<String>(); 1043 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords; 1044 if (oldRecords != null) { 1045 // Call dispose() on the obsolete update records. 1046 for (UpdateRecord record : oldRecords.values()) { 1047 record.disposeLocked(false); 1048 } 1049 // Accumulate providers 1050 providers.addAll(oldRecords.keySet()); 1051 } 1052 1053 // update provider 1054 for (String provider : providers) { 1055 // If provider is already disabled, don't need to do anything 1056 if (!isAllowedBySettingsLocked(provider)) { 1057 continue; 1058 } 1059 1060 applyRequirementsLocked(provider); 1061 } 1062 } 1063 1064 @Override 1065 public Location getLastLocation(LocationRequest request, String packageName) { 1066 if (D) Log.d(TAG, "getLastLocation: " + request); 1067 if (request == null) request = DEFAULT_LOCATION_REQUEST; 1068 String perm = checkPermissionAndRequest(request); 1069 checkPackageName(packageName); 1070 1071 if (mBlacklist.isBlacklisted(packageName)) { 1072 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " + 1073 packageName); 1074 return null; 1075 } 1076 1077 synchronized (mLock) { 1078 // Figure out the provider. Either its explicitly request (deprecated API's), 1079 // or use the fused provider 1080 String name = request.getProvider(); 1081 if (name == null) name = LocationManager.FUSED_PROVIDER; 1082 LocationProviderInterface provider = mProvidersByName.get(name); 1083 if (provider == null) return null; 1084 1085 if (!isAllowedBySettingsLocked(name)) return null; 1086 1087 Location location = mLastLocation.get(name); 1088 if (ACCESS_FINE_LOCATION.equals(perm)) { 1089 return location; 1090 } else { 1091 return mLocationFudger.getOrCreate(location); 1092 } 1093 } 1094 } 1095 1096 @Override 1097 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent, 1098 String packageName) { 1099 if (request == null) request = DEFAULT_LOCATION_REQUEST; 1100 checkPermissionAndRequest(request); 1101 checkPendingIntent(intent); 1102 checkPackageName(packageName); 1103 1104 if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent); 1105 1106 // geo-fence manager uses the public location API, need to clear identity 1107 int uid = Binder.getCallingUid(); 1108 long identity = Binder.clearCallingIdentity(); 1109 try { 1110 mGeofenceManager.addFence(request, geofence, intent, uid, packageName); 1111 } finally { 1112 Binder.restoreCallingIdentity(identity); 1113 } 1114 } 1115 1116 @Override 1117 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) { 1118 checkPermission(); 1119 checkPendingIntent(intent); 1120 checkPackageName(packageName); 1121 1122 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent); 1123 1124 // geo-fence manager uses the public location API, need to clear identity 1125 long identity = Binder.clearCallingIdentity(); 1126 try { 1127 mGeofenceManager.removeFence(geofence, intent); 1128 } finally { 1129 Binder.restoreCallingIdentity(identity); 1130 } 1131 } 1132 1133 1134 @Override 1135 public boolean addGpsStatusListener(IGpsStatusListener listener) { 1136 if (mGpsStatusProvider == null) { 1137 return false; 1138 } 1139 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) != 1140 PackageManager.PERMISSION_GRANTED) { 1141 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); 1142 } 1143 1144 try { 1145 mGpsStatusProvider.addGpsStatusListener(listener); 1146 } catch (RemoteException e) { 1147 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e); 1148 return false; 1149 } 1150 return true; 1151 } 1152 1153 @Override 1154 public void removeGpsStatusListener(IGpsStatusListener listener) { 1155 synchronized (mLock) { 1156 try { 1157 mGpsStatusProvider.removeGpsStatusListener(listener); 1158 } catch (Exception e) { 1159 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e); 1160 } 1161 } 1162 } 1163 1164 @Override 1165 public boolean sendExtraCommand(String provider, String command, Bundle extras) { 1166 if (provider == null) { 1167 // throw NullPointerException to remain compatible with previous implementation 1168 throw new NullPointerException(); 1169 } 1170 1171 checkPermission(); 1172 // and check for ACCESS_LOCATION_EXTRA_COMMANDS 1173 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS) 1174 != PackageManager.PERMISSION_GRANTED)) { 1175 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission"); 1176 } 1177 1178 synchronized (mLock) { 1179 LocationProviderInterface p = mProvidersByName.get(provider); 1180 if (p == null) return false; 1181 1182 return p.sendExtraCommand(command, extras); 1183 } 1184 } 1185 1186 @Override 1187 public boolean sendNiResponse(int notifId, int userResponse) { 1188 if (Binder.getCallingUid() != Process.myUid()) { 1189 throw new SecurityException( 1190 "calling sendNiResponse from outside of the system is not allowed"); 1191 } 1192 try { 1193 return mNetInitiatedListener.sendNiResponse(notifId, userResponse); 1194 } catch (RemoteException e) { 1195 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse"); 1196 return false; 1197 } 1198 } 1199 1200 /** 1201 * @return null if the provider does not exist 1202 * @throws SecurityException if the provider is not allowed to be 1203 * accessed by the caller 1204 */ 1205 @Override 1206 public ProviderProperties getProviderProperties(String provider) { 1207 checkPermission(); 1208 1209 LocationProviderInterface p; 1210 synchronized (mLock) { 1211 p = mProvidersByName.get(provider); 1212 } 1213 1214 if (p == null) return null; 1215 return p.getProperties(); 1216 } 1217 1218 @Override 1219 public boolean isProviderEnabled(String provider) { 1220 checkPermission(); 1221 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false; 1222 1223 synchronized (mLock) { 1224 LocationProviderInterface p = mProvidersByName.get(provider); 1225 if (p == null) return false; 1226 1227 return isAllowedBySettingsLocked(provider); 1228 } 1229 } 1230 1231 private void checkCallerIsProvider() { 1232 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER) 1233 == PackageManager.PERMISSION_GRANTED) { 1234 return; 1235 } 1236 1237 // Previously we only used the INSTALL_LOCATION_PROVIDER 1238 // check. But that is system or signature 1239 // protection level which is not flexible enough for 1240 // providers installed oustide the system image. So 1241 // also allow providers with a UID matching the 1242 // currently bound package name 1243 1244 int uid = Binder.getCallingUid(); 1245 1246 if (mGeocodeProvider != null) { 1247 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return; 1248 } 1249 for (LocationProviderProxy proxy : mProxyProviders) { 1250 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return; 1251 } 1252 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " + 1253 "or UID of a currently bound location provider"); 1254 } 1255 1256 private boolean doesPackageHaveUid(int uid, String packageName) { 1257 if (packageName == null) { 1258 return false; 1259 } 1260 try { 1261 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0); 1262 if (appInfo.uid != uid) { 1263 return false; 1264 } 1265 } catch (NameNotFoundException e) { 1266 return false; 1267 } 1268 return true; 1269 } 1270 1271 @Override 1272 public void reportLocation(Location location, boolean passive) { 1273 checkCallerIsProvider(); 1274 1275 if (!location.isComplete()) { 1276 Log.w(TAG, "Dropping incomplete location: " + location); 1277 return; 1278 } 1279 1280 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location); 1281 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location); 1282 m.arg1 = (passive ? 1 : 0); 1283 mLocationHandler.sendMessageAtFrontOfQueue(m); 1284 } 1285 1286 1287 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) { 1288 // Always broadcast the first update 1289 if (lastLoc == null) { 1290 return true; 1291 } 1292 1293 // Check whether sufficient time has passed 1294 long minTime = record.mRequest.getFastestInterval(); 1295 long delta = (loc.getElapsedRealtimeNano() - lastLoc.getElapsedRealtimeNano()) / 1000000L; 1296 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) { 1297 return false; 1298 } 1299 1300 // Check whether sufficient distance has been traveled 1301 double minDistance = record.mRequest.getSmallestDisplacement(); 1302 if (minDistance > 0.0) { 1303 if (loc.distanceTo(lastLoc) <= minDistance) { 1304 return false; 1305 } 1306 } 1307 1308 return true; 1309 } 1310 1311 private void handleLocationChangedLocked(Location location, boolean passive) { 1312 if (D) Log.d(TAG, "incoming location: " + location); 1313 1314 long now = SystemClock.elapsedRealtime(); 1315 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider()); 1316 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 1317 if (records == null || records.size() == 0) return; 1318 1319 LocationProviderInterface p = mProvidersByName.get(provider); 1320 if (p == null) return; 1321 1322 // Add the coarse location as an extra 1323 Location coarse = mLocationFudger.getOrCreate(location); 1324 1325 // Update last known locations 1326 Location lastLocation = mLastLocation.get(provider); 1327 if (lastLocation == null) { 1328 lastLocation = new Location(provider); 1329 mLastLocation.put(provider, lastLocation); 1330 } 1331 lastLocation.set(location); 1332 1333 // Fetch latest status update time 1334 long newStatusUpdateTime = p.getStatusUpdateTime(); 1335 1336 // Get latest status 1337 Bundle extras = new Bundle(); 1338 int status = p.getStatus(extras); 1339 1340 ArrayList<Receiver> deadReceivers = null; 1341 ArrayList<UpdateRecord> deadUpdateRecords = null; 1342 1343 // Broadcast location or status to all listeners 1344 for (UpdateRecord r : records) { 1345 Receiver receiver = r.mReceiver; 1346 boolean receiverDead = false; 1347 1348 if (mBlacklist.isBlacklisted(receiver.mPackageName)) { 1349 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " + 1350 receiver.mPackageName); 1351 continue; 1352 } 1353 1354 if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) { 1355 location = lastLocation; // use fine location 1356 } else { 1357 location = coarse; // use coarse location 1358 } 1359 1360 Location lastLoc = r.mLastFixBroadcast; 1361 if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) { 1362 if (lastLoc == null) { 1363 lastLoc = new Location(location); 1364 r.mLastFixBroadcast = lastLoc; 1365 } else { 1366 lastLoc.set(location); 1367 } 1368 if (!receiver.callLocationChangedLocked(location)) { 1369 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver); 1370 receiverDead = true; 1371 } 1372 } 1373 1374 long prevStatusUpdateTime = r.mLastStatusBroadcast; 1375 if ((newStatusUpdateTime > prevStatusUpdateTime) && 1376 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) { 1377 1378 r.mLastStatusBroadcast = newStatusUpdateTime; 1379 if (!receiver.callStatusChangedLocked(provider, status, extras)) { 1380 receiverDead = true; 1381 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver); 1382 } 1383 } 1384 1385 // track expired records 1386 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) { 1387 if (deadUpdateRecords == null) { 1388 deadUpdateRecords = new ArrayList<UpdateRecord>(); 1389 } 1390 deadUpdateRecords.add(r); 1391 } 1392 // track dead receivers 1393 if (receiverDead) { 1394 if (deadReceivers == null) { 1395 deadReceivers = new ArrayList<Receiver>(); 1396 } 1397 if (!deadReceivers.contains(receiver)) { 1398 deadReceivers.add(receiver); 1399 } 1400 } 1401 } 1402 1403 // remove dead records and receivers outside the loop 1404 if (deadReceivers != null) { 1405 for (Receiver receiver : deadReceivers) { 1406 removeUpdatesLocked(receiver); 1407 } 1408 } 1409 if (deadUpdateRecords != null) { 1410 for (UpdateRecord r : deadUpdateRecords) { 1411 r.disposeLocked(true); 1412 } 1413 } 1414 } 1415 1416 private class LocationWorkerHandler extends Handler { 1417 @Override 1418 public void handleMessage(Message msg) { 1419 switch (msg.what) { 1420 case MSG_LOCATION_CHANGED: 1421 handleLocationChanged((Location) msg.obj, msg.arg1 == 1); 1422 break; 1423 } 1424 } 1425 } 1426 1427 private void handleLocationChanged(Location location, boolean passive) { 1428 String provider = location.getProvider(); 1429 1430 if (!passive) { 1431 // notify passive provider of the new location 1432 mPassiveProvider.updateLocation(location); 1433 } 1434 1435 synchronized (mLock) { 1436 if (isAllowedBySettingsLocked(provider)) { 1437 handleLocationChangedLocked(location, passive); 1438 } 1439 } 1440 } 1441 1442 private final PackageMonitor mPackageMonitor = new PackageMonitor() { 1443 @Override 1444 public void onPackageDisappeared(String packageName, int reason) { 1445 // remove all receivers associated with this package name 1446 synchronized (mLock) { 1447 ArrayList<Receiver> deadReceivers = null; 1448 1449 for (Receiver receiver : mReceivers.values()) { 1450 if (receiver.mPackageName.equals(packageName)) { 1451 if (deadReceivers == null) { 1452 deadReceivers = new ArrayList<Receiver>(); 1453 } 1454 deadReceivers.add(receiver); 1455 } 1456 } 1457 1458 // perform removal outside of mReceivers loop 1459 if (deadReceivers != null) { 1460 for (Receiver receiver : deadReceivers) { 1461 removeUpdatesLocked(receiver); 1462 } 1463 } 1464 } 1465 } 1466 }; 1467 1468 // Wake locks 1469 1470 private void incrementPendingBroadcasts() { 1471 synchronized (mWakeLock) { 1472 if (mPendingBroadcasts++ == 0) { 1473 try { 1474 mWakeLock.acquire(); 1475 log("Acquired wakelock"); 1476 } catch (Exception e) { 1477 // This is to catch a runtime exception thrown when we try to release an 1478 // already released lock. 1479 Slog.e(TAG, "exception in acquireWakeLock()", e); 1480 } 1481 } 1482 } 1483 } 1484 1485 private void decrementPendingBroadcasts() { 1486 synchronized (mWakeLock) { 1487 if (--mPendingBroadcasts == 0) { 1488 try { 1489 // Release wake lock 1490 if (mWakeLock.isHeld()) { 1491 mWakeLock.release(); 1492 log("Released wakelock"); 1493 } else { 1494 log("Can't release wakelock again!"); 1495 } 1496 } catch (Exception e) { 1497 // This is to catch a runtime exception thrown when we try to release an 1498 // already released lock. 1499 Slog.e(TAG, "exception in releaseWakeLock()", e); 1500 } 1501 } 1502 } 1503 } 1504 1505 // Geocoder 1506 1507 @Override 1508 public boolean geocoderIsPresent() { 1509 return mGeocodeProvider != null; 1510 } 1511 1512 @Override 1513 public String getFromLocation(double latitude, double longitude, int maxResults, 1514 GeocoderParams params, List<Address> addrs) { 1515 if (mGeocodeProvider != null) { 1516 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, 1517 params, addrs); 1518 } 1519 return null; 1520 } 1521 1522 1523 @Override 1524 public String getFromLocationName(String locationName, 1525 double lowerLeftLatitude, double lowerLeftLongitude, 1526 double upperRightLatitude, double upperRightLongitude, int maxResults, 1527 GeocoderParams params, List<Address> addrs) { 1528 1529 if (mGeocodeProvider != null) { 1530 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude, 1531 lowerLeftLongitude, upperRightLatitude, upperRightLongitude, 1532 maxResults, params, addrs); 1533 } 1534 return null; 1535 } 1536 1537 // Mock Providers 1538 1539 private void checkMockPermissionsSafe() { 1540 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(), 1541 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1; 1542 if (!allowMocks) { 1543 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting"); 1544 } 1545 1546 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) != 1547 PackageManager.PERMISSION_GRANTED) { 1548 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission"); 1549 } 1550 } 1551 1552 @Override 1553 public void addTestProvider(String name, ProviderProperties properties) { 1554 checkMockPermissionsSafe(); 1555 1556 if (LocationManager.PASSIVE_PROVIDER.equals(name)) { 1557 throw new IllegalArgumentException("Cannot mock the passive location provider"); 1558 } 1559 1560 long identity = Binder.clearCallingIdentity(); 1561 synchronized (mLock) { 1562 MockProvider provider = new MockProvider(name, this, properties); 1563 // remove the real provider if we are replacing GPS or network provider 1564 if (LocationManager.GPS_PROVIDER.equals(name) 1565 || LocationManager.NETWORK_PROVIDER.equals(name) 1566 || LocationManager.FUSED_PROVIDER.equals(name)) { 1567 LocationProviderInterface p = mProvidersByName.get(name); 1568 if (p != null) { 1569 removeProviderLocked(p); 1570 } 1571 } 1572 if (mProvidersByName.get(name) != null) { 1573 throw new IllegalArgumentException("Provider \"" + name + "\" already exists"); 1574 } 1575 addProviderLocked(provider); 1576 mMockProviders.put(name, provider); 1577 mLastLocation.put(name, null); 1578 updateProvidersLocked(); 1579 } 1580 Binder.restoreCallingIdentity(identity); 1581 } 1582 1583 @Override 1584 public void removeTestProvider(String provider) { 1585 checkMockPermissionsSafe(); 1586 synchronized (mLock) { 1587 MockProvider mockProvider = mMockProviders.get(provider); 1588 if (mockProvider == null) { 1589 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1590 } 1591 long identity = Binder.clearCallingIdentity(); 1592 removeProviderLocked(mProvidersByName.get(provider)); 1593 mMockProviders.remove(mockProvider); 1594 1595 // reinstate real provider if available 1596 LocationProviderInterface realProvider = mRealProviders.get(provider); 1597 if (realProvider != null) { 1598 addProviderLocked(realProvider); 1599 } 1600 mLastLocation.put(provider, null); 1601 updateProvidersLocked(); 1602 Binder.restoreCallingIdentity(identity); 1603 } 1604 } 1605 1606 @Override 1607 public void setTestProviderLocation(String provider, Location loc) { 1608 checkMockPermissionsSafe(); 1609 synchronized (mLock) { 1610 MockProvider mockProvider = mMockProviders.get(provider); 1611 if (mockProvider == null) { 1612 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1613 } 1614 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required 1615 long identity = Binder.clearCallingIdentity(); 1616 mockProvider.setLocation(loc); 1617 Binder.restoreCallingIdentity(identity); 1618 } 1619 } 1620 1621 @Override 1622 public void clearTestProviderLocation(String provider) { 1623 checkMockPermissionsSafe(); 1624 synchronized (mLock) { 1625 MockProvider mockProvider = mMockProviders.get(provider); 1626 if (mockProvider == null) { 1627 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1628 } 1629 mockProvider.clearLocation(); 1630 } 1631 } 1632 1633 @Override 1634 public void setTestProviderEnabled(String provider, boolean enabled) { 1635 checkMockPermissionsSafe(); 1636 synchronized (mLock) { 1637 MockProvider mockProvider = mMockProviders.get(provider); 1638 if (mockProvider == null) { 1639 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1640 } 1641 long identity = Binder.clearCallingIdentity(); 1642 if (enabled) { 1643 mockProvider.enable(); 1644 mEnabledProviders.add(provider); 1645 mDisabledProviders.remove(provider); 1646 } else { 1647 mockProvider.disable(); 1648 mEnabledProviders.remove(provider); 1649 mDisabledProviders.add(provider); 1650 } 1651 updateProvidersLocked(); 1652 Binder.restoreCallingIdentity(identity); 1653 } 1654 } 1655 1656 @Override 1657 public void clearTestProviderEnabled(String provider) { 1658 checkMockPermissionsSafe(); 1659 synchronized (mLock) { 1660 MockProvider mockProvider = mMockProviders.get(provider); 1661 if (mockProvider == null) { 1662 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1663 } 1664 long identity = Binder.clearCallingIdentity(); 1665 mEnabledProviders.remove(provider); 1666 mDisabledProviders.remove(provider); 1667 updateProvidersLocked(); 1668 Binder.restoreCallingIdentity(identity); 1669 } 1670 } 1671 1672 @Override 1673 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) { 1674 checkMockPermissionsSafe(); 1675 synchronized (mLock) { 1676 MockProvider mockProvider = mMockProviders.get(provider); 1677 if (mockProvider == null) { 1678 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1679 } 1680 mockProvider.setStatus(status, extras, updateTime); 1681 } 1682 } 1683 1684 @Override 1685 public void clearTestProviderStatus(String provider) { 1686 checkMockPermissionsSafe(); 1687 synchronized (mLock) { 1688 MockProvider mockProvider = mMockProviders.get(provider); 1689 if (mockProvider == null) { 1690 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1691 } 1692 mockProvider.clearStatus(); 1693 } 1694 } 1695 1696 private void log(String log) { 1697 if (Log.isLoggable(TAG, Log.VERBOSE)) { 1698 Slog.d(TAG, log); 1699 } 1700 } 1701 1702 @Override 1703 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1704 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 1705 != PackageManager.PERMISSION_GRANTED) { 1706 pw.println("Permission Denial: can't dump LocationManagerService from from pid=" 1707 + Binder.getCallingPid() 1708 + ", uid=" + Binder.getCallingUid()); 1709 return; 1710 } 1711 1712 synchronized (mLock) { 1713 pw.println("Current Location Manager state:"); 1714 pw.println(" Location Listeners:"); 1715 for (Receiver receiver : mReceivers.values()) { 1716 pw.println(" " + receiver); 1717 } 1718 pw.println(" Records by Provider:"); 1719 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) { 1720 pw.println(" " + entry.getKey() + ":"); 1721 for (UpdateRecord record : entry.getValue()) { 1722 pw.println(" " + record); 1723 } 1724 } 1725 pw.println(" Last Known Locations:"); 1726 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) { 1727 String provider = entry.getKey(); 1728 Location location = entry.getValue(); 1729 pw.println(" " + provider + ": " + location); 1730 } 1731 1732 mGeofenceManager.dump(pw); 1733 1734 if (mEnabledProviders.size() > 0) { 1735 pw.println(" Enabled Providers:"); 1736 for (String i : mEnabledProviders) { 1737 pw.println(" " + i); 1738 } 1739 1740 } 1741 if (mDisabledProviders.size() > 0) { 1742 pw.println(" Disabled Providers:"); 1743 for (String i : mDisabledProviders) { 1744 pw.println(" " + i); 1745 } 1746 } 1747 pw.append(" "); 1748 mBlacklist.dump(pw); 1749 if (mMockProviders.size() > 0) { 1750 pw.println(" Mock Providers:"); 1751 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) { 1752 i.getValue().dump(pw, " "); 1753 } 1754 } 1755 1756 pw.append(" fudger: "); 1757 mLocationFudger.dump(fd, pw, args); 1758 1759 if (args.length > 0 && "short".equals(args[0])) { 1760 return; 1761 } 1762 for (LocationProviderInterface provider: mProviders) { 1763 pw.print(provider.getName() + " Internal State"); 1764 if (provider instanceof LocationProviderProxy) { 1765 LocationProviderProxy proxy = (LocationProviderProxy) provider; 1766 pw.print(" (" + proxy.getConnectedPackageName() + ")"); 1767 } 1768 pw.println(":"); 1769 provider.dump(fd, pw, args); 1770 } 1771 } 1772 } 1773} 1774