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