LocationManagerService.java revision 9637d474899d9725da8a41fdf92b9bd1a15d301e
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 java.io.BufferedReader; 20import java.io.File; 21import java.io.FileDescriptor; 22import java.io.FileReader; 23import java.io.FileWriter; 24import java.io.IOException; 25import java.io.PrintWriter; 26import java.util.ArrayList; 27import java.util.HashMap; 28import java.util.HashSet; 29import java.util.List; 30import java.util.Map; 31import java.util.Observable; 32import java.util.Observer; 33import java.util.Set; 34import java.util.regex.Pattern; 35 36import android.app.AlarmManager; 37import android.app.PendingIntent; 38import android.content.BroadcastReceiver; 39import android.content.ContentQueryMap; 40import android.content.ContentResolver; 41import android.content.Context; 42import android.content.Intent; 43import android.content.IntentFilter; 44import android.content.pm.PackageManager; 45import android.database.Cursor; 46import android.location.Address; 47import android.location.IGpsStatusListener; 48import android.location.ILocationListener; 49import android.location.ILocationManager; 50import android.location.Location; 51import android.location.LocationManager; 52import android.location.LocationProvider; 53import android.location.LocationProviderImpl; 54import android.net.ConnectivityManager; 55import android.net.Uri; 56import android.net.wifi.ScanResult; 57import android.net.wifi.WifiManager; 58import android.os.Binder; 59import android.os.Bundle; 60import android.os.Handler; 61import android.os.IBinder; 62import android.os.Message; 63import android.os.PowerManager; 64import android.os.RemoteException; 65import android.os.SystemClock; 66import android.provider.Settings; 67import android.telephony.CellLocation; 68import android.telephony.PhoneStateListener; 69import android.telephony.TelephonyManager; 70import android.util.Config; 71import android.util.Log; 72import android.util.PrintWriterPrinter; 73import android.util.SparseIntArray; 74 75import com.android.internal.app.IBatteryStats; 76import com.android.internal.location.CellState; 77import com.android.internal.location.GpsLocationProvider; 78import com.android.internal.location.ILocationCollector; 79import com.android.internal.location.INetworkLocationManager; 80import com.android.internal.location.INetworkLocationProvider; 81import com.android.internal.location.MockProvider; 82import com.android.internal.location.TrackProvider; 83import com.android.server.am.BatteryStatsService; 84 85/** 86 * The service class that manages LocationProviders and issues location 87 * updates and alerts. 88 * 89 * {@hide} 90 */ 91public class LocationManagerService extends ILocationManager.Stub 92 implements INetworkLocationManager { 93 private static final String TAG = "LocationManagerService"; 94 private static final boolean LOCAL_LOGV = false; 95 96 // Minimum time interval between last known location writes, in milliseconds. 97 private static final long MIN_LAST_KNOWN_LOCATION_TIME = 60L * 1000L; 98 99 // Max time to hold wake lock for, in milliseconds. 100 private static final long MAX_TIME_FOR_WAKE_LOCK = 60 * 1000L; 101 102 // Time to wait after releasing a wake lock for clients to process location update, 103 // in milliseconds. 104 private static final long TIME_AFTER_WAKE_LOCK = 2 * 1000L; 105 106 // The last time a location was written, by provider name. 107 private HashMap<String,Long> mLastWriteTime = new HashMap<String,Long>(); 108 109 private static final Pattern PATTERN_COMMA = Pattern.compile(","); 110 111 private static final String ACCESS_FINE_LOCATION = 112 android.Manifest.permission.ACCESS_FINE_LOCATION; 113 private static final String ACCESS_COARSE_LOCATION = 114 android.Manifest.permission.ACCESS_COARSE_LOCATION; 115 private static final String ACCESS_MOCK_LOCATION = 116 android.Manifest.permission.ACCESS_MOCK_LOCATION; 117 private static final String ACCESS_LOCATION_EXTRA_COMMANDS = 118 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS; 119 120 // Set of providers that are explicitly enabled 121 private final Set<String> mEnabledProviders = new HashSet<String>(); 122 123 // Set of providers that are explicitly disabled 124 private final Set<String> mDisabledProviders = new HashSet<String>(); 125 126 // Locations, status values, and extras for mock providers 127 private final HashMap<String,MockProvider> mMockProviders = new HashMap<String,MockProvider>(); 128 129 private static boolean sProvidersLoaded = false; 130 131 private final Context mContext; 132 private GpsLocationProvider mGpsLocationProvider; 133 private boolean mGpsNavigating; 134 private LocationProviderImpl mNetworkLocationProvider; 135 private INetworkLocationProvider mNetworkLocationInterface; 136 private LocationWorkerHandler mLocationHandler; 137 138 // Handler messages 139 private static final int MESSAGE_HEARTBEAT = 1; 140 private static final int MESSAGE_ACQUIRE_WAKE_LOCK = 2; 141 private static final int MESSAGE_RELEASE_WAKE_LOCK = 3; 142 private static final int MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER = 4; 143 144 // Alarm manager and wakelock variables 145 private final static String ALARM_INTENT = "com.android.location.ALARM_INTENT"; 146 private final static String WAKELOCK_KEY = "LocationManagerService"; 147 private final static String WIFILOCK_KEY = "LocationManagerService"; 148 private AlarmManager mAlarmManager; 149 private long mAlarmInterval = 0; 150 private boolean mScreenOn = true; 151 private PowerManager.WakeLock mWakeLock = null; 152 private WifiManager.WifiLock mWifiLock = null; 153 private long mWakeLockAcquireTime = 0; 154 private boolean mWakeLockGpsReceived = true; 155 private boolean mWakeLockNetworkReceived = true; 156 private boolean mWifiWakeLockAcquired = false; 157 private boolean mCellWakeLockAcquired = false; 158 159 private final IBatteryStats mBatteryStats; 160 161 /** 162 * Mapping from listener IBinder/PendingIntent to local Listener wrappers. 163 */ 164 private final ArrayList<Receiver> mListeners = new ArrayList<Receiver>(); 165 166 /** 167 * Used for reporting which UIDs are causing the GPS to run. 168 */ 169 private final SparseIntArray mReportedGpsUids = new SparseIntArray(); 170 private int mReportedGpsSeq = 0; 171 172 /** 173 * Mapping from listener IBinder/PendingIntent to a map from provider name to UpdateRecord. 174 * This also serves as the lock for our state. 175 */ 176 private final HashMap<Receiver,HashMap<String,UpdateRecord>> mLocationListeners = 177 new HashMap<Receiver,HashMap<String,UpdateRecord>>(); 178 179 /** 180 * Mapping from listener IBinder/PendingIntent to a map from provider name to last broadcast 181 * location. 182 */ 183 private final HashMap<Receiver,HashMap<String,Location>> mLastFixBroadcast = 184 new HashMap<Receiver,HashMap<String,Location>>(); 185 private final HashMap<Receiver,HashMap<String,Long>> mLastStatusBroadcast = 186 new HashMap<Receiver,HashMap<String,Long>>(); 187 188 /** 189 * Mapping from provider name to all its UpdateRecords 190 */ 191 private final HashMap<String,ArrayList<UpdateRecord>> mRecordsByProvider = 192 new HashMap<String,ArrayList<UpdateRecord>>(); 193 194 /** 195 * Mappings from provider name to object to use for current location. Locations 196 * contained in this list may not always be valid. 197 */ 198 private final HashMap<String,Location> mLocationsByProvider = 199 new HashMap<String,Location>(); 200 201 // Proximity listeners 202 private Receiver mProximityListener = null; 203 private HashMap<PendingIntent,ProximityAlert> mProximityAlerts = 204 new HashMap<PendingIntent,ProximityAlert>(); 205 private HashSet<ProximityAlert> mProximitiesEntered = 206 new HashSet<ProximityAlert>(); 207 208 // Last known location for each provider 209 private HashMap<String,Location> mLastKnownLocation = 210 new HashMap<String,Location>(); 211 212 // Battery status extras (from com.android.server.BatteryService) 213 private static final String BATTERY_EXTRA_SCALE = "scale"; 214 private static final String BATTERY_EXTRA_LEVEL = "level"; 215 private static final String BATTERY_EXTRA_PLUGGED = "plugged"; 216 217 // Last known cell service state 218 private TelephonyManager mTelephonyManager; 219 220 // Location collector 221 private ILocationCollector mCollector; 222 223 // Wifi Manager 224 private WifiManager mWifiManager; 225 226 private int mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE; 227 private boolean mWifiEnabled = false; 228 229 // for Settings change notification 230 private ContentQueryMap mSettings; 231 232 /** 233 * A wrapper class holding either an ILocationListener or a PendingIntent to receive 234 * location updates. 235 */ 236 private final class Receiver implements IBinder.DeathRecipient { 237 final ILocationListener mListener; 238 final PendingIntent mPendingIntent; 239 final int mUid; 240 final Object mKey; 241 242 Receiver(ILocationListener listener, int uid) { 243 mListener = listener; 244 mPendingIntent = null; 245 mUid = uid; 246 mKey = listener.asBinder(); 247 } 248 249 Receiver(PendingIntent intent, int uid) { 250 mPendingIntent = intent; 251 mListener = null; 252 mUid = uid; 253 mKey = intent; 254 } 255 256 @Override 257 public boolean equals(Object otherObj) { 258 if (otherObj instanceof Receiver) { 259 return mKey.equals( 260 ((Receiver)otherObj).mKey); 261 } 262 return false; 263 } 264 265 @Override 266 public int hashCode() { 267 return mKey.hashCode(); 268 } 269 270 271 @Override 272 public String toString() { 273 if (mListener != null) { 274 return "Receiver{" 275 + Integer.toHexString(System.identityHashCode(this)) 276 + " uid " + mUid + " Listener " + mKey + "}"; 277 } else { 278 return "Receiver{" 279 + Integer.toHexString(System.identityHashCode(this)) 280 + " uid " + mUid + " Intent " + mKey + "}"; 281 } 282 } 283 284 public boolean isListener() { 285 return mListener != null; 286 } 287 288 public boolean isPendingIntent() { 289 return mPendingIntent != null; 290 } 291 292 public ILocationListener getListener() { 293 if (mListener != null) { 294 return mListener; 295 } 296 throw new IllegalStateException("Request for non-existent listener"); 297 } 298 299 public PendingIntent getPendingIntent() { 300 if (mPendingIntent != null) { 301 return mPendingIntent; 302 } 303 throw new IllegalStateException("Request for non-existent intent"); 304 } 305 306 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) { 307 if (mListener != null) { 308 try { 309 mListener.onStatusChanged(provider, status, extras); 310 } catch (RemoteException e) { 311 return false; 312 } 313 } else { 314 Intent statusChanged = new Intent(); 315 statusChanged.putExtras(extras); 316 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status); 317 try { 318 mPendingIntent.send(mContext, 0, statusChanged, null, null); 319 } catch (PendingIntent.CanceledException e) { 320 return false; 321 } 322 } 323 return true; 324 } 325 326 public boolean callLocationChangedLocked(Location location) { 327 if (mListener != null) { 328 try { 329 mListener.onLocationChanged(location); 330 } catch (RemoteException e) { 331 return false; 332 } 333 } else { 334 Intent locationChanged = new Intent(); 335 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location); 336 try { 337 mPendingIntent.send(mContext, 0, locationChanged, null, null); 338 } catch (PendingIntent.CanceledException e) { 339 return false; 340 } 341 } 342 return true; 343 } 344 345 public void binderDied() { 346 if (LOCAL_LOGV) { 347 Log.v(TAG, "Location listener died"); 348 } 349 synchronized (mLocationListeners) { 350 removeUpdatesLocked(this); 351 } 352 } 353 } 354 355 private final class SettingsObserver implements Observer { 356 public void update(Observable o, Object arg) { 357 synchronized (mLocationListeners) { 358 updateProvidersLocked(); 359 } 360 } 361 } 362 363 private Location readLastKnownLocationLocked(String provider) { 364 Location location = null; 365 String s = null; 366 try { 367 File f = new File(LocationManager.SYSTEM_DIR + "/location." 368 + provider); 369 if (!f.exists()) { 370 return null; 371 } 372 BufferedReader reader = new BufferedReader(new FileReader(f), 256); 373 s = reader.readLine(); 374 } catch (IOException e) { 375 Log.w(TAG, "Unable to read last known location", e); 376 } 377 378 if (s == null) { 379 return null; 380 } 381 try { 382 String[] tokens = PATTERN_COMMA.split(s); 383 int idx = 0; 384 long time = Long.parseLong(tokens[idx++]); 385 double latitude = Double.parseDouble(tokens[idx++]); 386 double longitude = Double.parseDouble(tokens[idx++]); 387 double altitude = Double.parseDouble(tokens[idx++]); 388 float bearing = Float.parseFloat(tokens[idx++]); 389 float speed = Float.parseFloat(tokens[idx++]); 390 391 location = new Location(provider); 392 location.setTime(time); 393 location.setLatitude(latitude); 394 location.setLongitude(longitude); 395 location.setAltitude(altitude); 396 location.setBearing(bearing); 397 location.setSpeed(speed); 398 } catch (NumberFormatException nfe) { 399 Log.e(TAG, "NumberFormatException reading last known location", nfe); 400 return null; 401 } 402 403 return location; 404 } 405 406 private void writeLastKnownLocationLocked(String provider, 407 Location location) { 408 long now = SystemClock.elapsedRealtime(); 409 Long last = mLastWriteTime.get(provider); 410 if ((last != null) 411 && (now - last.longValue() < MIN_LAST_KNOWN_LOCATION_TIME)) { 412 return; 413 } 414 mLastWriteTime.put(provider, now); 415 416 StringBuilder sb = new StringBuilder(100); 417 sb.append(location.getTime()); 418 sb.append(','); 419 sb.append(location.getLatitude()); 420 sb.append(','); 421 sb.append(location.getLongitude()); 422 sb.append(','); 423 sb.append(location.getAltitude()); 424 sb.append(','); 425 sb.append(location.getBearing()); 426 sb.append(','); 427 sb.append(location.getSpeed()); 428 429 FileWriter writer = null; 430 try { 431 File d = new File(LocationManager.SYSTEM_DIR); 432 if (!d.exists()) { 433 if (!d.mkdirs()) { 434 Log.w(TAG, "Unable to create directory to write location"); 435 return; 436 } 437 } 438 File f = new File(LocationManager.SYSTEM_DIR + "/location." + provider); 439 writer = new FileWriter(f); 440 writer.write(sb.toString()); 441 } catch (IOException e) { 442 Log.w(TAG, "Unable to write location", e); 443 } finally { 444 if (writer != null) { 445 try { 446 writer.close(); 447 } catch (IOException e) { 448 Log.w(TAG, "Exception closing file", e); 449 } 450 } 451 } 452 } 453 454 /** 455 * Load providers from /data/location/<provider_name>/ 456 * class 457 * kml 458 * nmea 459 * track 460 * location 461 * properties 462 */ 463 private void loadProviders() { 464 synchronized (mLocationListeners) { 465 if (sProvidersLoaded) { 466 return; 467 } 468 469 // Load providers 470 loadProvidersLocked(); 471 sProvidersLoaded = true; 472 } 473 } 474 475 private void loadProvidersLocked() { 476 try { 477 _loadProvidersLocked(); 478 } catch (Exception e) { 479 Log.e(TAG, "Exception loading providers:", e); 480 } 481 } 482 483 private void _loadProvidersLocked() { 484 // Attempt to load "real" providers first 485 if (GpsLocationProvider.isSupported()) { 486 // Create a gps location provider 487 mGpsLocationProvider = new GpsLocationProvider(mContext); 488 LocationProviderImpl.addProvider(mGpsLocationProvider); 489 } 490 491 // Load fake providers if real providers are not available 492 File f = new File(LocationManager.PROVIDER_DIR); 493 if (f.isDirectory()) { 494 File[] subdirs = f.listFiles(); 495 for (int i = 0; i < subdirs.length; i++) { 496 if (!subdirs[i].isDirectory()) { 497 continue; 498 } 499 500 String name = subdirs[i].getName(); 501 502 if (LOCAL_LOGV) { 503 Log.v(TAG, "Found dir " + subdirs[i].getAbsolutePath()); 504 Log.v(TAG, "name = " + name); 505 } 506 507 // Don't create a fake provider if a real provider exists 508 if (LocationProviderImpl.getProvider(name) == null) { 509 LocationProviderImpl provider = null; 510 try { 511 File classFile = new File(subdirs[i], "class"); 512 // Look for a 'class' file 513 provider = LocationProviderImpl.loadFromClass(classFile); 514 515 // Look for an 'kml', 'nmea', or 'track' file 516 if (provider == null) { 517 // Load properties from 'properties' file, if present 518 File propertiesFile = new File(subdirs[i], "properties"); 519 520 if (propertiesFile.exists()) { 521 provider = new TrackProvider(name); 522 ((TrackProvider)provider).readProperties(propertiesFile); 523 524 File kmlFile = new File(subdirs[i], "kml"); 525 if (kmlFile.exists()) { 526 ((TrackProvider) provider).readKml(kmlFile); 527 } else { 528 File nmeaFile = new File(subdirs[i], "nmea"); 529 if (nmeaFile.exists()) { 530 ((TrackProvider) provider).readNmea(name, nmeaFile); 531 } else { 532 File trackFile = new File(subdirs[i], "track"); 533 if (trackFile.exists()) { 534 ((TrackProvider) provider).readTrack(trackFile); 535 } 536 } 537 } 538 } 539 } 540 if (provider != null) { 541 LocationProviderImpl.addProvider(provider); 542 } 543 // Grab the initial location of a TrackProvider and 544 // store it as the last known location for that provider 545 if (provider instanceof TrackProvider) { 546 TrackProvider tp = (TrackProvider) provider; 547 mLastKnownLocation.put(tp.getName(), tp.getInitialLocation()); 548 } 549 } catch (Exception e) { 550 Log.e(TAG, "Exception loading provder " + name, e); 551 } 552 } 553 } 554 } 555 556 updateProvidersLocked(); 557 } 558 559 /** 560 * @param context the context that the LocationManagerService runs in 561 */ 562 public LocationManagerService(Context context) { 563 super(); 564 mContext = context; 565 mLocationHandler = new LocationWorkerHandler(); 566 567 if (LOCAL_LOGV) { 568 Log.v(TAG, "Constructed LocationManager Service"); 569 } 570 571 // Alarm manager, needs to be done before calling loadProviders() below 572 mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 573 574 // Create a wake lock, needs to be done before calling loadProviders() below 575 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 576 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); 577 578 // Battery statistics service to be notified when GPS turns on or off 579 mBatteryStats = BatteryStatsService.getService(); 580 581 // Load providers 582 loadProviders(); 583 584 // Listen for Radio changes 585 mTelephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); 586 mTelephonyManager.listen(mPhoneStateListener, 587 PhoneStateListener.LISTEN_CELL_LOCATION | 588 PhoneStateListener.LISTEN_SIGNAL_STRENGTH | 589 PhoneStateListener.LISTEN_DATA_CONNECTION_STATE); 590 591 // Register for Network (Wifi or Mobile) updates 592 NetworkStateBroadcastReceiver networkReceiver = new NetworkStateBroadcastReceiver(); 593 IntentFilter networkIntentFilter = new IntentFilter(); 594 networkIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 595 networkIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 596 networkIntentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 597 networkIntentFilter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION); 598 context.registerReceiver(networkReceiver, networkIntentFilter); 599 600 // Register for power updates 601 PowerStateBroadcastReceiver powerStateReceiver = new PowerStateBroadcastReceiver(); 602 IntentFilter intentFilter = new IntentFilter(); 603 intentFilter.addAction(ALARM_INTENT); 604 intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 605 intentFilter.addAction(Intent.ACTION_SCREEN_ON); 606 intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); 607 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 608 intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); 609 context.registerReceiver(powerStateReceiver, intentFilter); 610 611 // listen for settings changes 612 ContentResolver resolver = mContext.getContentResolver(); 613 Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null, 614 "(" + Settings.System.NAME + "=?)", 615 new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED}, 616 null); 617 mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mLocationHandler); 618 SettingsObserver settingsObserver = new SettingsObserver(); 619 mSettings.addObserver(settingsObserver); 620 621 // Get the wifi manager 622 mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); 623 624 // Create a wifi lock for future use 625 mWifiLock = getWifiWakelockLocked(); 626 } 627 628 public void setInstallCallback(InstallCallback callback) { 629 synchronized (mLocationListeners) { 630 mLocationHandler.removeMessages(MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER); 631 Message m = Message.obtain(mLocationHandler, 632 MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER, callback); 633 mLocationHandler.sendMessageAtFrontOfQueue(m); 634 } 635 } 636 637 public void setNetworkLocationProvider(INetworkLocationProvider provider) { 638 synchronized (mLocationListeners) { 639 mNetworkLocationInterface = provider; 640 provider.addListener(getPackageNames()); 641 mNetworkLocationProvider = (LocationProviderImpl)provider; 642 LocationProviderImpl.addProvider(mNetworkLocationProvider); 643 updateProvidersLocked(); 644 645 // notify NetworkLocationProvider of any events it might have missed 646 synchronized (mLocationListeners) { 647 mNetworkLocationProvider.updateNetworkState(mNetworkState); 648 mNetworkLocationInterface.updateWifiEnabledState(mWifiEnabled); 649 mNetworkLocationInterface.updateCellLockStatus(mCellWakeLockAcquired); 650 651 if (mLastCellState != null) { 652 if (mCollector != null) { 653 mCollector.updateCellState(mLastCellState); 654 } 655 mNetworkLocationProvider.updateCellState(mLastCellState); 656 } 657 658 // There might be an existing wifi scan available 659 if (mWifiManager != null) { 660 List<ScanResult> wifiScanResults = mWifiManager.getScanResults(); 661 if (wifiScanResults != null && wifiScanResults.size() != 0) { 662 mNetworkLocationInterface.updateWifiScanResults(wifiScanResults); 663 if (mCollector != null) { 664 mCollector.updateWifiScanResults(wifiScanResults); 665 } 666 } 667 } 668 } 669 } 670 } 671 672 public void setLocationCollector(ILocationCollector collector) { 673 synchronized (mLocationListeners) { 674 mCollector = collector; 675 if (mGpsLocationProvider != null) { 676 mGpsLocationProvider.setLocationCollector(mCollector); 677 } 678 } 679 } 680 681 private WifiManager.WifiLock getWifiWakelockLocked() { 682 if (mWifiLock == null && mWifiManager != null) { 683 mWifiLock = mWifiManager.createWifiLock(WifiManager.WIFI_MODE_SCAN_ONLY, WIFILOCK_KEY); 684 mWifiLock.setReferenceCounted(false); 685 } 686 return mWifiLock; 687 } 688 689 private boolean isAllowedBySettingsLocked(String provider) { 690 if (mEnabledProviders.contains(provider)) { 691 return true; 692 } 693 if (mDisabledProviders.contains(provider)) { 694 return false; 695 } 696 // Use system settings 697 ContentResolver resolver = mContext.getContentResolver(); 698 String allowedProviders = Settings.Secure.getString(resolver, 699 Settings.Secure.LOCATION_PROVIDERS_ALLOWED); 700 701 return ((allowedProviders != null) && (allowedProviders.contains(provider))); 702 } 703 704 private void checkPermissionsSafe(String provider) { 705 if (LocationManager.GPS_PROVIDER.equals(provider) 706 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) 707 != PackageManager.PERMISSION_GRANTED)) { 708 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); 709 } 710 if (LocationManager.NETWORK_PROVIDER.equals(provider) 711 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) 712 != PackageManager.PERMISSION_GRANTED) 713 && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION) 714 != PackageManager.PERMISSION_GRANTED)) { 715 throw new SecurityException( 716 "Requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission"); 717 } 718 } 719 720 private boolean isAllowedProviderSafe(String provider) { 721 if (LocationManager.GPS_PROVIDER.equals(provider) 722 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) 723 != PackageManager.PERMISSION_GRANTED)) { 724 return false; 725 } 726 if (LocationManager.NETWORK_PROVIDER.equals(provider) 727 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) 728 != PackageManager.PERMISSION_GRANTED) 729 && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION) 730 != PackageManager.PERMISSION_GRANTED)) { 731 return false; 732 } 733 734 return true; 735 } 736 737 private String[] getPackageNames() { 738 // Since a single UID may correspond to multiple packages, this can only be used as an 739 // approximation for tracking 740 return mContext.getPackageManager().getPackagesForUid(Binder.getCallingUid()); 741 } 742 743 public List<String> getAllProviders() { 744 try { 745 synchronized (mLocationListeners) { 746 return _getAllProvidersLocked(); 747 } 748 } catch (SecurityException se) { 749 throw se; 750 } catch (Exception e) { 751 Log.e(TAG, "getAllProviders got exception:", e); 752 return null; 753 } 754 } 755 756 private List<String> _getAllProvidersLocked() { 757 if (LOCAL_LOGV) { 758 Log.v(TAG, "getAllProviders"); 759 } 760 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders(); 761 ArrayList<String> out = new ArrayList<String>(providers.size()); 762 763 for (LocationProviderImpl p : providers) { 764 out.add(p.getName()); 765 } 766 return out; 767 } 768 769 public List<String> getProviders(boolean enabledOnly) { 770 try { 771 synchronized (mLocationListeners) { 772 return _getProvidersLocked(enabledOnly); 773 } 774 } catch (SecurityException se) { 775 throw se; 776 } catch (Exception e) { 777 Log.e(TAG, "getProviders got exception:", e); 778 return null; 779 } 780 } 781 782 private List<String> _getProvidersLocked(boolean enabledOnly) { 783 if (LOCAL_LOGV) { 784 Log.v(TAG, "getProviders"); 785 } 786 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders(); 787 ArrayList<String> out = new ArrayList<String>(); 788 789 for (LocationProviderImpl p : providers) { 790 String name = p.getName(); 791 if (isAllowedProviderSafe(name)) { 792 if (enabledOnly && !isAllowedBySettingsLocked(name)) { 793 continue; 794 } 795 out.add(name); 796 } 797 } 798 return out; 799 } 800 801 private void updateProvidersLocked() { 802 for (LocationProviderImpl p : LocationProviderImpl.getProviders()) { 803 boolean isEnabled = p.isEnabled(); 804 String name = p.getName(); 805 boolean shouldBeEnabled = isAllowedBySettingsLocked(name); 806 807 // Collection is only allowed when network provider is being used 808 if (mCollector != null && 809 p.getName().equals(LocationManager.NETWORK_PROVIDER)) { 810 mCollector.updateNetworkProviderStatus(shouldBeEnabled); 811 } 812 813 if (isEnabled && !shouldBeEnabled) { 814 updateProviderListenersLocked(name, false); 815 } else if (!isEnabled && shouldBeEnabled) { 816 updateProviderListenersLocked(name, true); 817 } 818 819 } 820 } 821 822 private void updateProviderListenersLocked(String provider, boolean enabled) { 823 int listeners = 0; 824 825 LocationProviderImpl p = LocationProviderImpl.getProvider(provider); 826 if (p == null) { 827 return; 828 } 829 830 ArrayList<Receiver> deadReceivers = null; 831 832 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 833 if (records != null) { 834 final int N = records.size(); 835 for (int i=0; i<N; i++) { 836 UpdateRecord record = records.get(i); 837 // Sends a notification message to the receiver 838 try { 839 Receiver receiver = record.mReceiver; 840 if (receiver.isListener()) { 841 if (enabled) { 842 receiver.getListener().onProviderEnabled(provider); 843 } else { 844 receiver.getListener().onProviderDisabled(provider); 845 } 846 } else { 847 Intent providerIntent = new Intent(); 848 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled); 849 try { 850 receiver.getPendingIntent().send(mContext, 0, 851 providerIntent, null, null); 852 } catch (PendingIntent.CanceledException e) { 853 if (deadReceivers == null) { 854 deadReceivers = new ArrayList<Receiver>(); 855 deadReceivers.add(receiver); 856 } 857 } 858 } 859 } catch (RemoteException e) { 860 // The death link will clean this up. 861 } 862 listeners++; 863 } 864 } 865 866 if (deadReceivers != null) { 867 for (int i=deadReceivers.size()-1; i>=0; i--) { 868 removeUpdatesLocked(deadReceivers.get(i)); 869 } 870 } 871 872 if (enabled) { 873 p.enable(); 874 if (listeners > 0) { 875 p.setMinTime(getMinTimeLocked(provider)); 876 p.enableLocationTracking(true); 877 updateWakelockStatusLocked(mScreenOn); 878 } 879 } else { 880 p.enableLocationTracking(false); 881 if (p == mGpsLocationProvider) { 882 mGpsNavigating = false; 883 reportStopGpsLocked(); 884 } 885 p.disable(); 886 updateWakelockStatusLocked(mScreenOn); 887 } 888 889 if (enabled && listeners > 0) { 890 mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider); 891 Message m = Message.obtain(mLocationHandler, MESSAGE_HEARTBEAT, provider); 892 mLocationHandler.sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000); 893 } else { 894 mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider); 895 } 896 } 897 898 private long getMinTimeLocked(String provider) { 899 long minTime = Long.MAX_VALUE; 900 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 901 if (records != null) { 902 for (int i=records.size()-1; i>=0; i--) { 903 minTime = Math.min(minTime, records.get(i).mMinTime); 904 } 905 } 906 return minTime; 907 } 908 909 private class UpdateRecord { 910 final String mProvider; 911 final Receiver mReceiver; 912 final long mMinTime; 913 final float mMinDistance; 914 final int mUid; 915 final String[] mPackages; 916 917 /** 918 * Note: must be constructed with lock held. 919 */ 920 UpdateRecord(String provider, long minTime, float minDistance, 921 Receiver receiver, int uid, String[] packages) { 922 mProvider = provider; 923 mReceiver = receiver; 924 mMinTime = minTime; 925 mMinDistance = minDistance; 926 mUid = uid; 927 mPackages = packages; 928 929 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 930 if (records == null) { 931 records = new ArrayList<UpdateRecord>(); 932 mRecordsByProvider.put(provider, records); 933 } 934 if (!records.contains(this)) { 935 records.add(this); 936 } 937 } 938 939 /** 940 * Method to be called when a record will no longer be used. Calling this multiple times 941 * must have the same effect as calling it once. 942 */ 943 void disposeLocked() { 944 ArrayList<UpdateRecord> records = mRecordsByProvider.get(this.mProvider); 945 records.remove(this); 946 } 947 948 @Override 949 public String toString() { 950 return "UpdateRecord{" 951 + Integer.toHexString(System.identityHashCode(this)) 952 + " " + mProvider + " " + mReceiver + "}"; 953 } 954 955 void dump(PrintWriter pw, String prefix) { 956 pw.println(prefix + this); 957 pw.println(prefix + "mProvider=" + mProvider + " mReceiver=" + mReceiver); 958 pw.println(prefix + "mMinTime=" + mMinTime + " mMinDistance=" + mMinDistance); 959 StringBuilder sb = new StringBuilder(); 960 if (mPackages != null) { 961 for (int i=0; i<mPackages.length; i++) { 962 if (i > 0) sb.append(", "); 963 sb.append(mPackages[i]); 964 } 965 } 966 pw.println(prefix + "mUid=" + mUid + " mPackages=" + sb); 967 } 968 969 /** 970 * Calls dispose(). 971 */ 972 @Override protected void finalize() { 973 synchronized (mLocationListeners) { 974 disposeLocked(); 975 } 976 } 977 } 978 979 public void requestLocationUpdates(String provider, 980 long minTime, float minDistance, ILocationListener listener) { 981 982 try { 983 synchronized (mLocationListeners) { 984 requestLocationUpdatesLocked(provider, minTime, minDistance, 985 new Receiver(listener, Binder.getCallingUid())); 986 } 987 } catch (SecurityException se) { 988 throw se; 989 } catch (Exception e) { 990 Log.e(TAG, "requestUpdates got exception:", e); 991 } 992 } 993 994 public void requestLocationUpdatesPI(String provider, 995 long minTime, float minDistance, PendingIntent intent) { 996 try { 997 synchronized (mLocationListeners) { 998 requestLocationUpdatesLocked(provider, minTime, minDistance, 999 new Receiver(intent, Binder.getCallingUid())); 1000 } 1001 } catch (SecurityException se) { 1002 throw se; 1003 } catch (Exception e) { 1004 Log.e(TAG, "requestUpdates got exception:", e); 1005 } 1006 } 1007 1008 private void requestLocationUpdatesLocked(String provider, 1009 long minTime, float minDistance, Receiver receiver) { 1010 if (LOCAL_LOGV) { 1011 Log.v(TAG, "_requestLocationUpdates: listener = " + receiver); 1012 } 1013 1014 LocationProviderImpl impl = LocationProviderImpl.getProvider(provider); 1015 if (impl == null) { 1016 throw new IllegalArgumentException("provider=" + provider); 1017 } 1018 1019 checkPermissionsSafe(provider); 1020 1021 String[] packages = getPackageNames(); 1022 1023 // so wakelock calls will succeed 1024 final int callingUid = Binder.getCallingUid(); 1025 long identity = Binder.clearCallingIdentity(); 1026 try { 1027 UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, 1028 receiver, callingUid, packages); 1029 if (!mListeners.contains(receiver)) { 1030 try { 1031 if (receiver.isListener()) { 1032 receiver.getListener().asBinder().linkToDeath(receiver, 0); 1033 } 1034 mListeners.add(receiver); 1035 } catch (RemoteException e) { 1036 return; 1037 } 1038 } 1039 1040 HashMap<String,UpdateRecord> records = mLocationListeners.get(receiver); 1041 if (records == null) { 1042 records = new HashMap<String,UpdateRecord>(); 1043 mLocationListeners.put(receiver, records); 1044 } 1045 UpdateRecord oldRecord = records.put(provider, r); 1046 if (oldRecord != null) { 1047 oldRecord.disposeLocked(); 1048 } 1049 1050 boolean isProviderEnabled = isAllowedBySettingsLocked(provider); 1051 if (isProviderEnabled) { 1052 long minTimeForProvider = getMinTimeLocked(provider); 1053 impl.setMinTime(minTimeForProvider); 1054 impl.enableLocationTracking(true); 1055 updateWakelockStatusLocked(mScreenOn); 1056 1057 if (provider.equals(LocationManager.GPS_PROVIDER)) { 1058 if (mGpsNavigating) { 1059 updateReportedGpsLocked(); 1060 } 1061 } 1062 1063 // Clear heartbeats if any before starting a new one 1064 mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider); 1065 Message m = Message.obtain(mLocationHandler, MESSAGE_HEARTBEAT, provider); 1066 mLocationHandler.sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000); 1067 } else { 1068 try { 1069 // Notify the listener that updates are currently disabled 1070 if (receiver.isListener()) { 1071 receiver.getListener().onProviderDisabled(provider); 1072 } 1073 } catch(RemoteException e) { 1074 Log.w(TAG, "RemoteException calling onProviderDisabled on " + 1075 receiver.getListener()); 1076 } 1077 } 1078 } finally { 1079 Binder.restoreCallingIdentity(identity); 1080 } 1081 } 1082 1083 public void removeUpdates(ILocationListener listener) { 1084 try { 1085 synchronized (mLocationListeners) { 1086 removeUpdatesLocked(new Receiver(listener, Binder.getCallingUid())); 1087 } 1088 } catch (SecurityException se) { 1089 throw se; 1090 } catch (Exception e) { 1091 Log.e(TAG, "removeUpdates got exception:", e); 1092 } 1093 } 1094 1095 public void removeUpdatesPI(PendingIntent intent) { 1096 try { 1097 synchronized (mLocationListeners) { 1098 removeUpdatesLocked(new Receiver(intent, Binder.getCallingUid())); 1099 } 1100 } catch (SecurityException se) { 1101 throw se; 1102 } catch (Exception e) { 1103 Log.e(TAG, "removeUpdates got exception:", e); 1104 } 1105 } 1106 1107 private void removeUpdatesLocked(Receiver receiver) { 1108 if (LOCAL_LOGV) { 1109 Log.v(TAG, "_removeUpdates: listener = " + receiver); 1110 } 1111 1112 // so wakelock calls will succeed 1113 final int callingUid = Binder.getCallingUid(); 1114 long identity = Binder.clearCallingIdentity(); 1115 try { 1116 int idx = mListeners.indexOf(receiver); 1117 if (idx >= 0) { 1118 Receiver myReceiver = mListeners.remove(idx); 1119 if (myReceiver.isListener()) { 1120 myReceiver.getListener().asBinder().unlinkToDeath(myReceiver, 0); 1121 } 1122 } 1123 1124 // Record which providers were associated with this listener 1125 HashSet<String> providers = new HashSet<String>(); 1126 HashMap<String,UpdateRecord> oldRecords = mLocationListeners.get(receiver); 1127 if (oldRecords != null) { 1128 // Call dispose() on the obsolete update records. 1129 for (UpdateRecord record : oldRecords.values()) { 1130 if (record.mProvider.equals(LocationManager.NETWORK_PROVIDER)) { 1131 if (mNetworkLocationInterface != null) { 1132 mNetworkLocationInterface.removeListener(record.mPackages); 1133 } 1134 } 1135 record.disposeLocked(); 1136 } 1137 // Accumulate providers 1138 providers.addAll(oldRecords.keySet()); 1139 } 1140 1141 mLocationListeners.remove(receiver); 1142 mLastFixBroadcast.remove(receiver); 1143 mLastStatusBroadcast.remove(receiver); 1144 1145 // See if the providers associated with this listener have any 1146 // other listeners; if one does, inform it of the new smallest minTime 1147 // value; if one does not, disable location tracking for it 1148 for (String provider : providers) { 1149 // If provider is already disabled, don't need to do anything 1150 if (!isAllowedBySettingsLocked(provider)) { 1151 continue; 1152 } 1153 1154 boolean hasOtherListener = false; 1155 ArrayList<UpdateRecord> recordsForProvider = mRecordsByProvider.get(provider); 1156 if (recordsForProvider != null && recordsForProvider.size() > 0) { 1157 hasOtherListener = true; 1158 } 1159 1160 LocationProviderImpl p = LocationProviderImpl.getProvider(provider); 1161 if (p != null) { 1162 if (hasOtherListener) { 1163 p.setMinTime(getMinTimeLocked(provider)); 1164 } else { 1165 mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider); 1166 p.enableLocationTracking(false); 1167 } 1168 1169 if (p == mGpsLocationProvider && mGpsNavigating) { 1170 updateReportedGpsLocked(); 1171 } 1172 } 1173 } 1174 1175 updateWakelockStatusLocked(mScreenOn); 1176 } finally { 1177 Binder.restoreCallingIdentity(identity); 1178 } 1179 } 1180 1181 public boolean addGpsStatusListener(IGpsStatusListener listener) { 1182 if (mGpsLocationProvider == null) { 1183 return false; 1184 } 1185 if (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) != 1186 PackageManager.PERMISSION_GRANTED) { 1187 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); 1188 } 1189 1190 try { 1191 mGpsLocationProvider.addGpsStatusListener(listener); 1192 } catch (RemoteException e) { 1193 Log.w(TAG, "RemoteException in addGpsStatusListener"); 1194 return false; 1195 } 1196 return true; 1197 } 1198 1199 public void removeGpsStatusListener(IGpsStatusListener listener) { 1200 synchronized (mLocationListeners) { 1201 mGpsLocationProvider.removeGpsStatusListener(listener); 1202 } 1203 } 1204 1205 public boolean sendExtraCommand(String provider, String command, Bundle extras) { 1206 // first check for permission to the provider 1207 checkPermissionsSafe(provider); 1208 // and check for ACCESS_LOCATION_EXTRA_COMMANDS 1209 if ((mContext.checkCallingPermission(ACCESS_LOCATION_EXTRA_COMMANDS) 1210 != PackageManager.PERMISSION_GRANTED)) { 1211 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission"); 1212 } 1213 1214 synchronized (mLocationListeners) { 1215 LocationProviderImpl impl = LocationProviderImpl.getProvider(provider); 1216 if (provider == null) { 1217 return false; 1218 } 1219 1220 return impl.sendExtraCommand(command, extras); 1221 } 1222 } 1223 1224 class ProximityAlert { 1225 final int mUid; 1226 final double mLatitude; 1227 final double mLongitude; 1228 final float mRadius; 1229 final long mExpiration; 1230 final PendingIntent mIntent; 1231 final Location mLocation; 1232 1233 public ProximityAlert(int uid, double latitude, double longitude, 1234 float radius, long expiration, PendingIntent intent) { 1235 mUid = uid; 1236 mLatitude = latitude; 1237 mLongitude = longitude; 1238 mRadius = radius; 1239 mExpiration = expiration; 1240 mIntent = intent; 1241 1242 mLocation = new Location(""); 1243 mLocation.setLatitude(latitude); 1244 mLocation.setLongitude(longitude); 1245 } 1246 1247 long getExpiration() { 1248 return mExpiration; 1249 } 1250 1251 PendingIntent getIntent() { 1252 return mIntent; 1253 } 1254 1255 boolean isInProximity(double latitude, double longitude) { 1256 Location loc = new Location(""); 1257 loc.setLatitude(latitude); 1258 loc.setLongitude(longitude); 1259 1260 double radius = loc.distanceTo(mLocation); 1261 return radius <= mRadius; 1262 } 1263 1264 @Override 1265 public String toString() { 1266 return "ProximityAlert{" 1267 + Integer.toHexString(System.identityHashCode(this)) 1268 + " uid " + mUid + mIntent + "}"; 1269 } 1270 1271 void dump(PrintWriter pw, String prefix) { 1272 pw.println(prefix + this); 1273 pw.println(prefix + "mLatitude=" + mLatitude + " mLongitude=" + mLongitude); 1274 pw.println(prefix + "mRadius=" + mRadius + " mExpiration=" + mExpiration); 1275 pw.println(prefix + "mIntent=" + mIntent); 1276 pw.println(prefix + "mLocation:"); 1277 mLocation.dump(new PrintWriterPrinter(pw), prefix + " "); 1278 } 1279 } 1280 1281 // Listener for receiving locations to trigger proximity alerts 1282 class ProximityListener extends ILocationListener.Stub { 1283 1284 boolean isGpsAvailable = false; 1285 1286 // Note: this is called with the lock held. 1287 public void onLocationChanged(Location loc) { 1288 1289 // If Gps is available, then ignore updates from NetworkLocationProvider 1290 if (loc.getProvider().equals(LocationManager.GPS_PROVIDER)) { 1291 isGpsAvailable = true; 1292 } 1293 if (isGpsAvailable && loc.getProvider().equals(LocationManager.NETWORK_PROVIDER)) { 1294 return; 1295 } 1296 1297 // Process proximity alerts 1298 long now = System.currentTimeMillis(); 1299 double latitude = loc.getLatitude(); 1300 double longitude = loc.getLongitude(); 1301 ArrayList<PendingIntent> intentsToRemove = null; 1302 1303 for (ProximityAlert alert : mProximityAlerts.values()) { 1304 PendingIntent intent = alert.getIntent(); 1305 long expiration = alert.getExpiration(); 1306 1307 if ((expiration == -1) || (now <= expiration)) { 1308 boolean entered = mProximitiesEntered.contains(alert); 1309 boolean inProximity = 1310 alert.isInProximity(latitude, longitude); 1311 if (!entered && inProximity) { 1312 if (LOCAL_LOGV) { 1313 Log.v(TAG, "Entered alert"); 1314 } 1315 mProximitiesEntered.add(alert); 1316 Intent enteredIntent = new Intent(); 1317 enteredIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true); 1318 try { 1319 intent.send(mContext, 0, enteredIntent, null, null); 1320 } catch (PendingIntent.CanceledException e) { 1321 if (LOCAL_LOGV) { 1322 Log.v(TAG, "Canceled proximity alert: " + alert, e); 1323 } 1324 if (intentsToRemove == null) { 1325 intentsToRemove = new ArrayList<PendingIntent>(); 1326 } 1327 intentsToRemove.add(intent); 1328 } 1329 } else if (entered && !inProximity) { 1330 if (LOCAL_LOGV) { 1331 Log.v(TAG, "Exited alert"); 1332 } 1333 mProximitiesEntered.remove(alert); 1334 Intent exitedIntent = new Intent(); 1335 exitedIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false); 1336 try { 1337 intent.send(mContext, 0, exitedIntent, null, null); 1338 } catch (PendingIntent.CanceledException e) { 1339 if (LOCAL_LOGV) { 1340 Log.v(TAG, "Canceled proximity alert: " + alert, e); 1341 } 1342 if (intentsToRemove == null) { 1343 intentsToRemove = new ArrayList<PendingIntent>(); 1344 } 1345 intentsToRemove.add(intent); 1346 } 1347 } 1348 } else { 1349 // Mark alert for expiration 1350 if (LOCAL_LOGV) { 1351 Log.v(TAG, "Expiring proximity alert: " + alert); 1352 } 1353 if (intentsToRemove == null) { 1354 intentsToRemove = new ArrayList<PendingIntent>(); 1355 } 1356 intentsToRemove.add(alert.getIntent()); 1357 } 1358 } 1359 1360 // Remove expired alerts 1361 if (intentsToRemove != null) { 1362 for (PendingIntent i : intentsToRemove) { 1363 mProximityAlerts.remove(i); 1364 ProximityAlert alert = mProximityAlerts.get(i); 1365 mProximitiesEntered.remove(alert); 1366 } 1367 } 1368 1369 } 1370 1371 // Note: this is called with the lock held. 1372 public void onProviderDisabled(String provider) { 1373 if (provider.equals(LocationManager.GPS_PROVIDER)) { 1374 isGpsAvailable = false; 1375 } 1376 } 1377 1378 // Note: this is called with the lock held. 1379 public void onProviderEnabled(String provider) { 1380 // ignore 1381 } 1382 1383 // Note: this is called with the lock held. 1384 public void onStatusChanged(String provider, int status, Bundle extras) { 1385 if ((provider.equals(LocationManager.GPS_PROVIDER)) && 1386 (status != LocationProvider.AVAILABLE)) { 1387 isGpsAvailable = false; 1388 } 1389 } 1390 } 1391 1392 public void addProximityAlert(double latitude, double longitude, 1393 float radius, long expiration, PendingIntent intent) { 1394 try { 1395 synchronized (mLocationListeners) { 1396 addProximityAlertLocked(latitude, longitude, radius, expiration, intent); 1397 } 1398 } catch (SecurityException se) { 1399 throw se; 1400 } catch (Exception e) { 1401 Log.e(TAG, "addProximityAlert got exception:", e); 1402 } 1403 } 1404 1405 private void addProximityAlertLocked(double latitude, double longitude, 1406 float radius, long expiration, PendingIntent intent) { 1407 if (LOCAL_LOGV) { 1408 Log.v(TAG, "addProximityAlert: latitude = " + latitude + 1409 ", longitude = " + longitude + 1410 ", expiration = " + expiration + 1411 ", intent = " + intent); 1412 } 1413 1414 // Require ability to access all providers for now 1415 if (!isAllowedProviderSafe(LocationManager.GPS_PROVIDER) || 1416 !isAllowedProviderSafe(LocationManager.NETWORK_PROVIDER)) { 1417 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); 1418 } 1419 1420 if (expiration != -1) { 1421 expiration += System.currentTimeMillis(); 1422 } 1423 ProximityAlert alert = new ProximityAlert(Binder.getCallingUid(), 1424 latitude, longitude, radius, expiration, intent); 1425 mProximityAlerts.put(intent, alert); 1426 1427 if (mProximityListener == null) { 1428 mProximityListener = new Receiver(new ProximityListener(), -1); 1429 1430 LocationProvider provider = LocationProviderImpl.getProvider( 1431 LocationManager.GPS_PROVIDER); 1432 if (provider != null) { 1433 requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityListener); 1434 } 1435 1436 provider = 1437 LocationProviderImpl.getProvider(LocationManager.NETWORK_PROVIDER); 1438 if (provider != null) { 1439 requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityListener); 1440 } 1441 } else if (mGpsNavigating) { 1442 updateReportedGpsLocked(); 1443 } 1444 } 1445 1446 public void removeProximityAlert(PendingIntent intent) { 1447 try { 1448 synchronized (mLocationListeners) { 1449 removeProximityAlertLocked(intent); 1450 } 1451 } catch (SecurityException se) { 1452 throw se; 1453 } catch (Exception e) { 1454 Log.e(TAG, "removeProximityAlert got exception:", e); 1455 } 1456 } 1457 1458 private void removeProximityAlertLocked(PendingIntent intent) { 1459 if (LOCAL_LOGV) { 1460 Log.v(TAG, "removeProximityAlert: intent = " + intent); 1461 } 1462 1463 mProximityAlerts.remove(intent); 1464 if (mProximityAlerts.size() == 0) { 1465 removeUpdatesLocked(mProximityListener); 1466 mProximityListener = null; 1467 } else if (mGpsNavigating) { 1468 updateReportedGpsLocked(); 1469 } 1470 } 1471 1472 /** 1473 * @return null if the provider does not exits 1474 * @throw SecurityException if the provider is not allowed to be 1475 * accessed by the caller 1476 */ 1477 public Bundle getProviderInfo(String provider) { 1478 try { 1479 synchronized (mLocationListeners) { 1480 return _getProviderInfoLocked(provider); 1481 } 1482 } catch (SecurityException se) { 1483 throw se; 1484 } catch (Exception e) { 1485 Log.e(TAG, "_getProviderInfo got exception:", e); 1486 return null; 1487 } 1488 } 1489 1490 private Bundle _getProviderInfoLocked(String provider) { 1491 LocationProviderImpl p = LocationProviderImpl.getProvider(provider); 1492 if (p == null) { 1493 return null; 1494 } 1495 1496 checkPermissionsSafe(provider); 1497 1498 Bundle b = new Bundle(); 1499 b.putBoolean("network", p.requiresNetwork()); 1500 b.putBoolean("satellite", p.requiresSatellite()); 1501 b.putBoolean("cell", p.requiresCell()); 1502 b.putBoolean("cost", p.hasMonetaryCost()); 1503 b.putBoolean("altitude", p.supportsAltitude()); 1504 b.putBoolean("speed", p.supportsSpeed()); 1505 b.putBoolean("bearing", p.supportsBearing()); 1506 b.putInt("power", p.getPowerRequirement()); 1507 b.putInt("accuracy", p.getAccuracy()); 1508 1509 return b; 1510 } 1511 1512 public boolean isProviderEnabled(String provider) { 1513 try { 1514 synchronized (mLocationListeners) { 1515 return _isProviderEnabledLocked(provider); 1516 } 1517 } catch (SecurityException se) { 1518 throw se; 1519 } catch (Exception e) { 1520 Log.e(TAG, "isProviderEnabled got exception:", e); 1521 return false; 1522 } 1523 } 1524 1525 private boolean _isProviderEnabledLocked(String provider) { 1526 checkPermissionsSafe(provider); 1527 1528 LocationProviderImpl p = LocationProviderImpl.getProvider(provider); 1529 if (p == null) { 1530 throw new IllegalArgumentException("provider=" + provider); 1531 } 1532 return isAllowedBySettingsLocked(provider); 1533 } 1534 1535 public Location getLastKnownLocation(String provider) { 1536 try { 1537 synchronized (mLocationListeners) { 1538 return _getLastKnownLocationLocked(provider); 1539 } 1540 } catch (SecurityException se) { 1541 throw se; 1542 } catch (Exception e) { 1543 Log.e(TAG, "getLastKnownLocation got exception:", e); 1544 return null; 1545 } 1546 } 1547 1548 private Location _getLastKnownLocationLocked(String provider) { 1549 checkPermissionsSafe(provider); 1550 1551 LocationProviderImpl p = LocationProviderImpl.getProvider(provider); 1552 if (p == null) { 1553 throw new IllegalArgumentException("provider=" + provider); 1554 } 1555 1556 if (!isAllowedBySettingsLocked(provider)) { 1557 return null; 1558 } 1559 1560 Location location = mLastKnownLocation.get(provider); 1561 if (location == null) { 1562 // Get the persistent last known location for the provider 1563 location = readLastKnownLocationLocked(provider); 1564 if (location != null) { 1565 mLastKnownLocation.put(provider, location); 1566 } 1567 } 1568 1569 return location; 1570 } 1571 1572 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) { 1573 // Always broadcast the first update 1574 if (lastLoc == null) { 1575 return true; 1576 } 1577 1578 // Don't broadcast same location again regardless of condition 1579 // TODO - we should probably still rebroadcast if user explicitly sets a minTime > 0 1580 if (loc.getTime() == lastLoc.getTime()) { 1581 return false; 1582 } 1583 1584 // Check whether sufficient distance has been traveled 1585 double minDistance = record.mMinDistance; 1586 if (minDistance > 0.0) { 1587 if (loc.distanceTo(lastLoc) <= minDistance) { 1588 return false; 1589 } 1590 } 1591 1592 return true; 1593 } 1594 1595 private void handleLocationChangedLocked(String provider) { 1596 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 1597 if (records == null || records.size() == 0) { 1598 return; 1599 } 1600 1601 LocationProviderImpl p = LocationProviderImpl.getProvider(provider); 1602 if (p == null) { 1603 return; 1604 } 1605 1606 // Get location object 1607 Location loc = mLocationsByProvider.get(provider); 1608 if (loc == null) { 1609 loc = new Location(provider); 1610 mLocationsByProvider.put(provider, loc); 1611 } else { 1612 loc.reset(); 1613 } 1614 1615 boolean locationValid; 1616 1617 // Use the mock location if available 1618 MockProvider mockProvider = mMockProviders.get(provider); 1619 if (mockProvider != null && mockProvider.getLocation(loc)) { 1620 locationValid = true; 1621 } else { 1622 locationValid = p.getLocation(loc); 1623 } 1624 1625 // Update last known location for provider 1626 if (locationValid) { 1627 Location location = mLastKnownLocation.get(provider); 1628 if (location == null) { 1629 mLastKnownLocation.put(provider, new Location(loc)); 1630 } else { 1631 location.set(loc); 1632 } 1633 writeLastKnownLocationLocked(provider, loc); 1634 1635 if (p instanceof INetworkLocationProvider) { 1636 mWakeLockNetworkReceived = true; 1637 } else if (p instanceof GpsLocationProvider) { 1638 // Gps location received signal is in NetworkStateBroadcastReceiver 1639 } 1640 } 1641 1642 // Fetch latest status update time 1643 long newStatusUpdateTime = p.getStatusUpdateTime(); 1644 1645 // Get latest status 1646 Bundle extras = new Bundle(); 1647 int status = p.getStatus(extras); 1648 1649 // Override with mock values if mock provider is present 1650 if (mockProvider != null) { 1651 status = mockProvider.overrideStatus(status); 1652 newStatusUpdateTime = mockProvider.overrideStatusUpdateTime(newStatusUpdateTime); 1653 mockProvider.overrideExtras(extras); 1654 } 1655 1656 ArrayList<Receiver> deadReceivers = null; 1657 1658 // Broadcast location or status to all listeners 1659 final int N = records.size(); 1660 for (int i=0; i<N; i++) { 1661 UpdateRecord r = records.get(i); 1662 Receiver receiver = r.mReceiver; 1663 1664 // Broadcast location only if it is valid 1665 if (locationValid) { 1666 HashMap<String,Location> map = mLastFixBroadcast.get(receiver); 1667 if (map == null) { 1668 map = new HashMap<String,Location>(); 1669 mLastFixBroadcast.put(receiver, map); 1670 } 1671 Location lastLoc = map.get(provider); 1672 if ((lastLoc == null) || shouldBroadcastSafe(loc, lastLoc, r)) { 1673 if (lastLoc == null) { 1674 lastLoc = new Location(loc); 1675 map.put(provider, lastLoc); 1676 } else { 1677 lastLoc.set(loc); 1678 } 1679 if (!receiver.callLocationChangedLocked(loc)) { 1680 Log.w(TAG, "RemoteException calling onLocationChanged on " + receiver); 1681 if (deadReceivers == null) { 1682 deadReceivers = new ArrayList<Receiver>(); 1683 } 1684 deadReceivers.add(receiver); 1685 } 1686 } 1687 } 1688 1689 // Broadcast status message 1690 HashMap<String,Long> statusMap = mLastStatusBroadcast.get(receiver); 1691 if (statusMap == null) { 1692 statusMap = new HashMap<String,Long>(); 1693 mLastStatusBroadcast.put(receiver, statusMap); 1694 } 1695 long prevStatusUpdateTime = 1696 (statusMap.get(provider) != null) ? statusMap.get(provider) : 0; 1697 1698 if ((newStatusUpdateTime > prevStatusUpdateTime) && 1699 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) { 1700 1701 statusMap.put(provider, newStatusUpdateTime); 1702 if (!receiver.callStatusChangedLocked(provider, status, extras)) { 1703 Log.w(TAG, "RemoteException calling onStatusChanged on " + receiver); 1704 if (deadReceivers == null) { 1705 deadReceivers = new ArrayList<Receiver>(); 1706 } 1707 if (!deadReceivers.contains(receiver)) { 1708 deadReceivers.add(receiver); 1709 } 1710 } 1711 } 1712 } 1713 1714 if (deadReceivers != null) { 1715 for (int i=deadReceivers.size()-1; i>=0; i--) { 1716 removeUpdatesLocked(deadReceivers.get(i)); 1717 } 1718 } 1719 } 1720 1721 private class LocationWorkerHandler extends Handler { 1722 1723 @Override 1724 public void handleMessage(Message msg) { 1725 try { 1726 if (msg.what == MESSAGE_HEARTBEAT) { 1727 // log("LocationWorkerHandler: Heartbeat!"); 1728 1729 synchronized (mLocationListeners) { 1730 String provider = (String) msg.obj; 1731 if (!isAllowedBySettingsLocked(provider)) { 1732 return; 1733 } 1734 1735 // Process the location fix if the screen is on or we're holding a wakelock 1736 if (mScreenOn || (mWakeLockAcquireTime != 0)) { 1737 handleLocationChangedLocked(provider); 1738 } 1739 1740 // If it continues to have listeners 1741 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 1742 if (records != null && records.size() > 0) { 1743 Message m = Message.obtain(this, MESSAGE_HEARTBEAT, provider); 1744 sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000); 1745 } 1746 1747 if ((mWakeLockAcquireTime != 0) && 1748 (SystemClock.elapsedRealtime() - mWakeLockAcquireTime 1749 > MAX_TIME_FOR_WAKE_LOCK)) { 1750 1751 removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK); 1752 removeMessages(MESSAGE_RELEASE_WAKE_LOCK); 1753 1754 log("LocationWorkerHandler: Exceeded max time for wake lock"); 1755 Message m = Message.obtain(this, MESSAGE_RELEASE_WAKE_LOCK); 1756 sendMessageAtFrontOfQueue(m); 1757 1758 } else if (mWakeLockAcquireTime != 0 && 1759 mWakeLockGpsReceived && mWakeLockNetworkReceived) { 1760 1761 removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK); 1762 removeMessages(MESSAGE_RELEASE_WAKE_LOCK); 1763 1764 log("LocationWorkerHandler: Locations received."); 1765 mWakeLockAcquireTime = 0; 1766 Message m = Message.obtain(this, MESSAGE_RELEASE_WAKE_LOCK); 1767 sendMessageDelayed(m, TIME_AFTER_WAKE_LOCK); 1768 } 1769 } 1770 1771 } else if (msg.what == MESSAGE_ACQUIRE_WAKE_LOCK) { 1772 log("LocationWorkerHandler: Acquire"); 1773 synchronized (mLocationListeners) { 1774 acquireWakeLockLocked(); 1775 } 1776 } else if (msg.what == MESSAGE_RELEASE_WAKE_LOCK) { 1777 log("LocationWorkerHandler: Release"); 1778 1779 // Update wakelock status so the next alarm is set before releasing wakelock 1780 synchronized (mLocationListeners) { 1781 updateWakelockStatusLocked(mScreenOn); 1782 releaseWakeLockLocked(); 1783 } 1784 } else if (msg.what == MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER) { 1785 synchronized (mLocationListeners) { 1786 Log.d(TAG, "installing network location provider"); 1787 INetworkLocationManager.InstallCallback callback = 1788 (INetworkLocationManager.InstallCallback)msg.obj; 1789 callback.installNetworkLocationProvider(LocationManagerService.this); 1790 } 1791 } 1792 } catch (Exception e) { 1793 // Log, don't crash! 1794 Log.e(TAG, "Exception in LocationWorkerHandler.handleMessage:", e); 1795 } 1796 } 1797 } 1798 1799 class CellLocationUpdater extends Thread { 1800 CellLocation mNextLocation; 1801 1802 CellLocationUpdater() { 1803 super("CellLocationUpdater"); 1804 } 1805 1806 @Override 1807 public void run() { 1808 int curAsu = -1; 1809 CellLocation curLocation = null; 1810 1811 while (true) { 1812 // See if there is more work to do... 1813 synchronized (mLocationListeners) { 1814 if (curLocation == mNextLocation) { 1815 mCellLocationUpdater = null; 1816 break; 1817 } 1818 1819 curLocation = mNextLocation; 1820 if (curLocation == null) { 1821 mCellLocationUpdater = null; 1822 break; 1823 } 1824 1825 curAsu = mLastSignalStrength; 1826 1827 mNextLocation = null; 1828 } 1829 1830 try { 1831 // Gets cell state. This can block so must be done without 1832 // locks held. 1833 CellState cs = new CellState(mTelephonyManager, curLocation, curAsu); 1834 1835 synchronized (mLocationListeners) { 1836 mLastCellState = cs; 1837 1838 cs.updateSignalStrength(mLastSignalStrength); 1839 cs.updateRadioType(mLastRadioType); 1840 1841 // Notify collector 1842 if (mCollector != null) { 1843 mCollector.updateCellState(cs); 1844 } 1845 1846 // Updates providers 1847 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders(); 1848 for (LocationProviderImpl provider : providers) { 1849 if (provider.requiresCell()) { 1850 provider.updateCellState(cs); 1851 } 1852 } 1853 } 1854 } catch (RuntimeException e) { 1855 Log.e(TAG, "Exception in PhoneStateListener.onCellLocationChanged:", e); 1856 } 1857 } 1858 } 1859 } 1860 1861 CellLocationUpdater mCellLocationUpdater = null; 1862 CellState mLastCellState = null; 1863 int mLastSignalStrength = -1; 1864 int mLastRadioType = -1; 1865 1866 PhoneStateListener mPhoneStateListener = new PhoneStateListener() { 1867 1868 @Override 1869 public void onCellLocationChanged(CellLocation cellLocation) { 1870 synchronized (mLocationListeners) { 1871 if (mCellLocationUpdater == null) { 1872 mCellLocationUpdater = new CellLocationUpdater(); 1873 mCellLocationUpdater.start(); 1874 } 1875 mCellLocationUpdater.mNextLocation = cellLocation; 1876 } 1877 } 1878 1879 @Override 1880 public void onSignalStrengthChanged(int asu) { 1881 synchronized (mLocationListeners) { 1882 mLastSignalStrength = asu; 1883 1884 if (mLastCellState != null) { 1885 mLastCellState.updateSignalStrength(asu); 1886 } 1887 } 1888 } 1889 1890 @Override 1891 public void onDataConnectionStateChanged(int state) { 1892 synchronized (mLocationListeners) { 1893 // Get radio type 1894 int radioType = mTelephonyManager.getNetworkType(); 1895 if (radioType == TelephonyManager.NETWORK_TYPE_GPRS || 1896 radioType == TelephonyManager.NETWORK_TYPE_EDGE) { 1897 radioType = CellState.RADIO_TYPE_GPRS; 1898 } else if (radioType == TelephonyManager.NETWORK_TYPE_UMTS) { 1899 radioType = CellState.RADIO_TYPE_WCDMA; 1900 } 1901 mLastRadioType = radioType; 1902 1903 if (mLastCellState != null) { 1904 mLastCellState.updateRadioType(radioType); 1905 } 1906 } 1907 } 1908 }; 1909 1910 private class PowerStateBroadcastReceiver extends BroadcastReceiver { 1911 @Override public void onReceive(Context context, Intent intent) { 1912 String action = intent.getAction(); 1913 1914 if (action.equals(ALARM_INTENT)) { 1915 synchronized (mLocationListeners) { 1916 log("PowerStateBroadcastReceiver: Alarm received"); 1917 mLocationHandler.removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK); 1918 // Have to do this immediately, rather than posting a 1919 // message, so we execute our code while the system 1920 // is holding a wake lock until the alarm broadcast 1921 // is finished. 1922 acquireWakeLockLocked(); 1923 } 1924 1925 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 1926 log("PowerStateBroadcastReceiver: Screen off"); 1927 synchronized (mLocationListeners) { 1928 updateWakelockStatusLocked(false); 1929 } 1930 1931 } else if (action.equals(Intent.ACTION_SCREEN_ON)) { 1932 log("PowerStateBroadcastReceiver: Screen on"); 1933 synchronized (mLocationListeners) { 1934 updateWakelockStatusLocked(true); 1935 } 1936 1937 } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { 1938 log("PowerStateBroadcastReceiver: Battery changed"); 1939 synchronized (mLocationListeners) { 1940 int scale = intent.getIntExtra(BATTERY_EXTRA_SCALE, 100); 1941 int level = intent.getIntExtra(BATTERY_EXTRA_LEVEL, 0); 1942 boolean plugged = intent.getIntExtra(BATTERY_EXTRA_PLUGGED, 0) != 0; 1943 1944 // Notify collector battery state 1945 if (mCollector != null) { 1946 mCollector.updateBatteryState(scale, level, plugged); 1947 } 1948 } 1949 } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED) 1950 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)) { 1951 synchronized (mLocationListeners) { 1952 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); 1953 if (uid >= 0) { 1954 ArrayList<Receiver> removedRecs = null; 1955 for (ArrayList<UpdateRecord> i : mRecordsByProvider.values()) { 1956 for (int j=i.size()-1; j>=0; j--) { 1957 UpdateRecord ur = i.get(j); 1958 if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) { 1959 if (removedRecs == null) { 1960 removedRecs = new ArrayList<Receiver>(); 1961 } 1962 if (!removedRecs.contains(ur.mReceiver)) { 1963 removedRecs.add(ur.mReceiver); 1964 } 1965 } 1966 } 1967 } 1968 ArrayList<ProximityAlert> removedAlerts = null; 1969 for (ProximityAlert i : mProximityAlerts.values()) { 1970 if (i.mUid == uid) { 1971 if (removedAlerts == null) { 1972 removedAlerts = new ArrayList<ProximityAlert>(); 1973 } 1974 if (!removedAlerts.contains(i)) { 1975 removedAlerts.add(i); 1976 } 1977 } 1978 } 1979 if (removedRecs != null) { 1980 for (int i=removedRecs.size()-1; i>=0; i--) { 1981 removeUpdatesLocked(removedRecs.get(i)); 1982 } 1983 } 1984 if (removedAlerts != null) { 1985 for (int i=removedAlerts.size()-1; i>=0; i--) { 1986 removeProximityAlertLocked(removedAlerts.get(i).mIntent); 1987 } 1988 } 1989 } 1990 } 1991 } 1992 } 1993 } 1994 1995 private class NetworkStateBroadcastReceiver extends BroadcastReceiver { 1996 @Override public void onReceive(Context context, Intent intent) { 1997 String action = intent.getAction(); 1998 1999 if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { 2000 2001 List<ScanResult> wifiScanResults = mWifiManager.getScanResults(); 2002 2003 if (wifiScanResults == null) { 2004 return; 2005 } 2006 2007 // Notify provider and collector of Wifi scan results 2008 synchronized (mLocationListeners) { 2009 if (mCollector != null) { 2010 mCollector.updateWifiScanResults(wifiScanResults); 2011 } 2012 if (mNetworkLocationInterface != null) { 2013 mNetworkLocationInterface.updateWifiScanResults(wifiScanResults); 2014 } 2015 } 2016 2017 } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 2018 boolean noConnectivity = 2019 intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); 2020 if (!noConnectivity) { 2021 mNetworkState = LocationProvider.AVAILABLE; 2022 } else { 2023 mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE; 2024 } 2025 2026 // Notify location providers of current network state 2027 synchronized (mLocationListeners) { 2028 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders(); 2029 for (LocationProviderImpl provider : providers) { 2030 if (provider.requiresNetwork()) { 2031 provider.updateNetworkState(mNetworkState); 2032 } 2033 } 2034 } 2035 2036 } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { 2037 int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 2038 WifiManager.WIFI_STATE_UNKNOWN); 2039 2040 if (state == WifiManager.WIFI_STATE_ENABLED) { 2041 mWifiEnabled = true; 2042 } else if (state == WifiManager.WIFI_STATE_DISABLED) { 2043 mWifiEnabled = false; 2044 } else { 2045 return; 2046 } 2047 2048 // Notify network provider of current wifi enabled state 2049 synchronized (mLocationListeners) { 2050 if (mNetworkLocationInterface != null) { 2051 mNetworkLocationInterface.updateWifiEnabledState(mWifiEnabled); 2052 } 2053 } 2054 2055 } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION)) { 2056 2057 final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED, 2058 false); 2059 2060 synchronized (mLocationListeners) { 2061 if (enabled) { 2062 updateReportedGpsLocked(); 2063 mGpsNavigating = true; 2064 } else { 2065 reportStopGpsLocked(); 2066 mGpsNavigating = false; 2067 // When GPS is disabled, we are OK to release wake-lock 2068 mWakeLockGpsReceived = true; 2069 } 2070 } 2071 } 2072 2073 } 2074 } 2075 2076 // Wake locks 2077 2078 private void updateWakelockStatusLocked(boolean screenOn) { 2079 log("updateWakelockStatus(): " + screenOn); 2080 2081 long callerId = Binder.clearCallingIdentity(); 2082 2083 boolean needsLock = false; 2084 long minTime = Integer.MAX_VALUE; 2085 2086 if (mNetworkLocationProvider != null && mNetworkLocationProvider.isLocationTracking()) { 2087 needsLock = true; 2088 minTime = Math.min(mNetworkLocationProvider.getMinTime(), minTime); 2089 } 2090 2091 if (mGpsLocationProvider != null && mGpsLocationProvider.isLocationTracking()) { 2092 needsLock = true; 2093 minTime = Math.min(mGpsLocationProvider.getMinTime(), minTime); 2094 if (screenOn) { 2095 startGpsLocked(); 2096 } else if (mScreenOn && !screenOn) { 2097 // We just turned the screen off so stop navigating 2098 stopGpsLocked(); 2099 } 2100 } 2101 2102 mScreenOn = screenOn; 2103 2104 PendingIntent sender = 2105 PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_INTENT), 0); 2106 2107 // Cancel existing alarm 2108 log("Cancelling existing alarm"); 2109 mAlarmManager.cancel(sender); 2110 2111 if (needsLock && !mScreenOn) { 2112 long now = SystemClock.elapsedRealtime(); 2113 mAlarmManager.set( 2114 AlarmManager.ELAPSED_REALTIME_WAKEUP, now + minTime, sender); 2115 mAlarmInterval = minTime; 2116 log("Creating a new wakelock alarm with minTime = " + minTime); 2117 } else { 2118 log("No need for alarm"); 2119 mAlarmInterval = -1; 2120 2121 // Clear out existing wakelocks 2122 mLocationHandler.removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK); 2123 mLocationHandler.removeMessages(MESSAGE_RELEASE_WAKE_LOCK); 2124 releaseWakeLockLocked(); 2125 } 2126 Binder.restoreCallingIdentity(callerId); 2127 } 2128 2129 private void acquireWakeLockLocked() { 2130 try { 2131 acquireWakeLockXLocked(); 2132 } catch (Exception e) { 2133 // This is to catch a runtime exception thrown when we try to release an 2134 // already released lock. 2135 Log.e(TAG, "exception in acquireWakeLock()", e); 2136 } 2137 } 2138 2139 private void acquireWakeLockXLocked() { 2140 if (mWakeLock.isHeld()) { 2141 log("Must release wakelock before acquiring"); 2142 mWakeLockAcquireTime = 0; 2143 mWakeLock.release(); 2144 } 2145 2146 boolean networkActive = (mNetworkLocationProvider != null) 2147 && mNetworkLocationProvider.isLocationTracking(); 2148 boolean gpsActive = (mGpsLocationProvider != null) 2149 && mGpsLocationProvider.isLocationTracking(); 2150 2151 boolean needsLock = networkActive || gpsActive; 2152 if (!needsLock) { 2153 log("No need for Lock!"); 2154 return; 2155 } 2156 2157 mWakeLockGpsReceived = !gpsActive; 2158 mWakeLockNetworkReceived = !networkActive; 2159 2160 // Acquire wake lock 2161 mWakeLock.acquire(); 2162 mWakeLockAcquireTime = SystemClock.elapsedRealtime(); 2163 log("Acquired wakelock"); 2164 2165 // Start the gps provider 2166 startGpsLocked(); 2167 2168 // Acquire cell lock 2169 if (mCellWakeLockAcquired) { 2170 // Lock is already acquired 2171 } else if (!mWakeLockNetworkReceived) { 2172 mTelephonyManager.enableLocationUpdates(); 2173 mCellWakeLockAcquired = true; 2174 } else { 2175 mCellWakeLockAcquired = false; 2176 } 2177 2178 // Notify NetworkLocationProvider 2179 if (mNetworkLocationInterface != null) { 2180 mNetworkLocationInterface.updateCellLockStatus(mCellWakeLockAcquired); 2181 } 2182 2183 // Acquire wifi lock 2184 WifiManager.WifiLock wifiLock = getWifiWakelockLocked(); 2185 if (wifiLock != null) { 2186 if (mWifiWakeLockAcquired) { 2187 // Lock is already acquired 2188 } else if (mWifiManager.isWifiEnabled() && !mWakeLockNetworkReceived) { 2189 wifiLock.acquire(); 2190 mWifiWakeLockAcquired = true; 2191 } else { 2192 mWifiWakeLockAcquired = false; 2193 Log.w(TAG, "acquireWakeLock(): Unable to get WiFi lock"); 2194 } 2195 } 2196 } 2197 2198 private boolean reportGpsUidLocked(int curSeq, int nextSeq, int uid) { 2199 int seq = mReportedGpsUids.get(uid, -1); 2200 if (seq == curSeq) { 2201 // Already reported; propagate to next sequence. 2202 mReportedGpsUids.put(uid, nextSeq); 2203 return true; 2204 } else if (seq != nextSeq) { 2205 try { 2206 // New UID; report it. 2207 mBatteryStats.noteStartGps(uid); 2208 mReportedGpsUids.put(uid, nextSeq); 2209 return true; 2210 } catch (RemoteException e) { 2211 } 2212 } 2213 return false; 2214 } 2215 2216 private void updateReportedGpsLocked() { 2217 if (mGpsLocationProvider == null) { 2218 return; 2219 } 2220 2221 final String name = mGpsLocationProvider.getName(); 2222 final int curSeq = mReportedGpsSeq; 2223 final int nextSeq = (curSeq+1) >= 0 ? (curSeq+1) : 0; 2224 mReportedGpsSeq = nextSeq; 2225 2226 ArrayList<UpdateRecord> urs = mRecordsByProvider.get(name); 2227 int num = 0; 2228 final int N = urs.size(); 2229 for (int i=0; i<N; i++) { 2230 UpdateRecord ur = urs.get(i); 2231 if (ur.mReceiver == mProximityListener) { 2232 // We don't want the system to take the blame for this one. 2233 continue; 2234 } 2235 if (reportGpsUidLocked(curSeq, nextSeq, ur.mUid)) { 2236 num++; 2237 } 2238 } 2239 2240 for (ProximityAlert pe : mProximityAlerts.values()) { 2241 if (reportGpsUidLocked(curSeq, nextSeq, pe.mUid)) { 2242 num++; 2243 } 2244 } 2245 2246 if (num != mReportedGpsUids.size()) { 2247 // The number of uids is processed is different than the 2248 // array; report any that are no longer active. 2249 for (int i=mReportedGpsUids.size()-1; i>=0; i--) { 2250 if (mReportedGpsUids.valueAt(i) != nextSeq) { 2251 try { 2252 mBatteryStats.noteStopGps(mReportedGpsUids.keyAt(i)); 2253 } catch (RemoteException e) { 2254 } 2255 mReportedGpsUids.removeAt(i); 2256 } 2257 } 2258 } 2259 } 2260 2261 private void reportStopGpsLocked() { 2262 int curSeq = mReportedGpsSeq; 2263 for (int i=mReportedGpsUids.size()-1; i>=0; i--) { 2264 if (mReportedGpsUids.valueAt(i) == curSeq) { 2265 try { 2266 mBatteryStats.noteStopGps(mReportedGpsUids.keyAt(i)); 2267 } catch (RemoteException e) { 2268 } 2269 } 2270 } 2271 curSeq++; 2272 if (curSeq < 0) curSeq = 0; 2273 mReportedGpsSeq = curSeq; 2274 mReportedGpsUids.clear(); 2275 } 2276 2277 private void startGpsLocked() { 2278 boolean gpsActive = (mGpsLocationProvider != null) 2279 && mGpsLocationProvider.isLocationTracking(); 2280 if (gpsActive) { 2281 mGpsLocationProvider.startNavigating(); 2282 } 2283 } 2284 2285 private void stopGpsLocked() { 2286 boolean gpsActive = mGpsLocationProvider != null 2287 && mGpsLocationProvider.isLocationTracking(); 2288 if (gpsActive) { 2289 mGpsLocationProvider.stopNavigating(); 2290 } 2291 } 2292 2293 private void releaseWakeLockLocked() { 2294 try { 2295 releaseWakeLockXLocked(); 2296 } catch (Exception e) { 2297 // This is to catch a runtime exception thrown when we try to release an 2298 // already released lock. 2299 Log.e(TAG, "exception in releaseWakeLock()", e); 2300 } 2301 } 2302 2303 private void releaseWakeLockXLocked() { 2304 // Release wifi lock 2305 WifiManager.WifiLock wifiLock = getWifiWakelockLocked(); 2306 if (wifiLock != null) { 2307 if (mWifiWakeLockAcquired) { 2308 wifiLock.release(); 2309 mWifiWakeLockAcquired = false; 2310 } 2311 } 2312 2313 if (!mScreenOn) { 2314 // Stop the gps 2315 stopGpsLocked(); 2316 } 2317 2318 // Release cell lock 2319 if (mCellWakeLockAcquired) { 2320 mTelephonyManager.disableLocationUpdates(); 2321 mCellWakeLockAcquired = false; 2322 } 2323 2324 // Notify NetworkLocationProvider 2325 if (mNetworkLocationInterface != null) { 2326 mNetworkLocationInterface.updateCellLockStatus(mCellWakeLockAcquired); 2327 } 2328 2329 // Release wake lock 2330 mWakeLockAcquireTime = 0; 2331 if (mWakeLock.isHeld()) { 2332 log("Released wakelock"); 2333 mWakeLock.release(); 2334 } else { 2335 log("Can't release wakelock again!"); 2336 } 2337 } 2338 2339 // Geocoder 2340 2341 public String getFromLocation(double latitude, double longitude, int maxResults, 2342 String language, String country, String variant, String appName, List<Address> addrs) { 2343 synchronized (mLocationListeners) { 2344 if (mNetworkLocationInterface != null) { 2345 return mNetworkLocationInterface.getFromLocation(latitude, longitude, maxResults, 2346 language, country, variant, appName, addrs); 2347 } else { 2348 return null; 2349 } 2350 } 2351 } 2352 2353 public String getFromLocationName(String locationName, 2354 double lowerLeftLatitude, double lowerLeftLongitude, 2355 double upperRightLatitude, double upperRightLongitude, int maxResults, 2356 String language, String country, String variant, String appName, List<Address> addrs) { 2357 synchronized (mLocationListeners) { 2358 if (mNetworkLocationInterface != null) { 2359 return mNetworkLocationInterface.getFromLocationName(locationName, lowerLeftLatitude, 2360 lowerLeftLongitude, upperRightLatitude, upperRightLongitude, maxResults, 2361 language, country, variant, appName, addrs); 2362 } else { 2363 return null; 2364 } 2365 } 2366 } 2367 2368 // Mock Providers 2369 2370 private void checkMockPermissionsSafe() { 2371 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(), 2372 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1; 2373 if (!allowMocks) { 2374 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting"); 2375 } 2376 2377 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) != 2378 PackageManager.PERMISSION_GRANTED) { 2379 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission"); 2380 } 2381 } 2382 2383 public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite, 2384 boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, 2385 boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) { 2386 checkMockPermissionsSafe(); 2387 2388 synchronized (mLocationListeners) { 2389 MockProvider provider = new MockProvider(name, requiresNetwork, requiresSatellite, 2390 requiresCell, hasMonetaryCost, supportsAltitude, 2391 supportsSpeed, supportsBearing, powerRequirement, accuracy); 2392 if (LocationProviderImpl.getProvider(name) != null) { 2393 throw new IllegalArgumentException("Provider \"" + name + "\" already exists"); 2394 } 2395 LocationProviderImpl.addProvider(provider); 2396 mMockProviders.put(name, provider); 2397 updateProvidersLocked(); 2398 } 2399 } 2400 2401 public void removeTestProvider(String provider) { 2402 checkMockPermissionsSafe(); 2403 synchronized (mLocationListeners) { 2404 MockProvider mockProvider = mMockProviders.get(provider); 2405 if (mockProvider == null) { 2406 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2407 } 2408 LocationProviderImpl.removeProvider(mockProvider); 2409 mMockProviders.remove(mockProvider); 2410 updateProvidersLocked(); 2411 } 2412 } 2413 2414 public void setTestProviderLocation(String provider, Location loc) { 2415 checkMockPermissionsSafe(); 2416 synchronized (mLocationListeners) { 2417 MockProvider mockProvider = mMockProviders.get(provider); 2418 if (mockProvider == null) { 2419 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2420 } 2421 mockProvider.setLocation(loc); 2422 } 2423 } 2424 2425 public void clearTestProviderLocation(String provider) { 2426 checkMockPermissionsSafe(); 2427 synchronized (mLocationListeners) { 2428 MockProvider mockProvider = mMockProviders.get(provider); 2429 if (mockProvider == null) { 2430 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2431 } 2432 mockProvider.clearLocation(); 2433 } 2434 } 2435 2436 public void setTestProviderEnabled(String provider, boolean enabled) { 2437 checkMockPermissionsSafe(); 2438 synchronized (mLocationListeners) { 2439 MockProvider mockProvider = mMockProviders.get(provider); 2440 if (mockProvider == null) { 2441 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2442 } 2443 if (enabled) { 2444 mockProvider.enable(); 2445 mEnabledProviders.add(provider); 2446 mDisabledProviders.remove(provider); 2447 } else { 2448 mockProvider.disable(); 2449 mEnabledProviders.remove(provider); 2450 mDisabledProviders.add(provider); 2451 } 2452 updateProvidersLocked(); 2453 } 2454 } 2455 2456 public void clearTestProviderEnabled(String provider) { 2457 checkMockPermissionsSafe(); 2458 synchronized (mLocationListeners) { 2459 MockProvider mockProvider = mMockProviders.get(provider); 2460 if (mockProvider == null) { 2461 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2462 } 2463 mEnabledProviders.remove(provider); 2464 mDisabledProviders.remove(provider); 2465 updateProvidersLocked(); 2466 } 2467 } 2468 2469 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) { 2470 checkMockPermissionsSafe(); 2471 synchronized (mLocationListeners) { 2472 MockProvider mockProvider = mMockProviders.get(provider); 2473 if (mockProvider == null) { 2474 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2475 } 2476 mockProvider.setStatus(status, extras, updateTime); 2477 } 2478 } 2479 2480 public void clearTestProviderStatus(String provider) { 2481 checkMockPermissionsSafe(); 2482 synchronized (mLocationListeners) { 2483 MockProvider mockProvider = mMockProviders.get(provider); 2484 if (mockProvider == null) { 2485 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2486 } 2487 mockProvider.clearStatus(); 2488 } 2489 } 2490 2491 private void log(String log) { 2492 if (Log.isLoggable(TAG, Log.VERBOSE)) { 2493 Log.d(TAG, log); 2494 } 2495 } 2496 2497 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2498 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 2499 != PackageManager.PERMISSION_GRANTED) { 2500 pw.println("Permission Denial: can't dump AlarmManager from from pid=" 2501 + Binder.getCallingPid() 2502 + ", uid=" + Binder.getCallingUid()); 2503 return; 2504 } 2505 2506 synchronized (mLocationListeners) { 2507 pw.println("Current Location Manager state:"); 2508 pw.println(" sProvidersLoaded=" + sProvidersLoaded); 2509 pw.println(" mGpsLocationProvider=" + mGpsLocationProvider); 2510 pw.println(" mGpsNavigating=" + mGpsNavigating); 2511 pw.println(" mNetworkLocationProvider=" + mNetworkLocationProvider); 2512 pw.println(" mNetworkLocationInterface=" + mNetworkLocationInterface); 2513 pw.println(" mLastSignalStrength=" + mLastSignalStrength 2514 + " mLastRadioType=" + mLastRadioType); 2515 pw.println(" mCellLocationUpdater=" + mCellLocationUpdater); 2516 pw.println(" mLastCellState=" + mLastCellState); 2517 pw.println(" mCollector=" + mCollector); 2518 pw.println(" mAlarmInterval=" + mAlarmInterval 2519 + " mScreenOn=" + mScreenOn 2520 + " mWakeLockAcquireTime=" + mWakeLockAcquireTime); 2521 pw.println(" mWakeLockGpsReceived=" + mWakeLockGpsReceived 2522 + " mWakeLockNetworkReceived=" + mWakeLockNetworkReceived); 2523 pw.println(" mWifiWakeLockAcquired=" + mWifiWakeLockAcquired 2524 + " mCellWakeLockAcquired=" + mCellWakeLockAcquired); 2525 pw.println(" Listeners:"); 2526 int N = mListeners.size(); 2527 for (int i=0; i<N; i++) { 2528 pw.println(" " + mListeners.get(i)); 2529 } 2530 pw.println(" Location Listeners:"); 2531 for (Map.Entry<Receiver, HashMap<String,UpdateRecord>> i 2532 : mLocationListeners.entrySet()) { 2533 pw.println(" " + i.getKey() + ":"); 2534 for (Map.Entry<String,UpdateRecord> j : i.getValue().entrySet()) { 2535 pw.println(" " + j.getKey() + ":"); 2536 j.getValue().dump(pw, " "); 2537 } 2538 } 2539 pw.println(" Last Fix Broadcasts:"); 2540 for (Map.Entry<Receiver, HashMap<String,Location>> i 2541 : mLastFixBroadcast.entrySet()) { 2542 pw.println(" " + i.getKey() + ":"); 2543 for (Map.Entry<String,Location> j : i.getValue().entrySet()) { 2544 pw.println(" " + j.getKey() + ":"); 2545 j.getValue().dump(new PrintWriterPrinter(pw), " "); 2546 } 2547 } 2548 pw.println(" Last Status Broadcasts:"); 2549 for (Map.Entry<Receiver, HashMap<String,Long>> i 2550 : mLastStatusBroadcast.entrySet()) { 2551 pw.println(" " + i.getKey() + ":"); 2552 for (Map.Entry<String,Long> j : i.getValue().entrySet()) { 2553 pw.println(" " + j.getKey() + " -> 0x" 2554 + Long.toHexString(j.getValue())); 2555 } 2556 } 2557 pw.println(" Records by Provider:"); 2558 for (Map.Entry<String, ArrayList<UpdateRecord>> i 2559 : mRecordsByProvider.entrySet()) { 2560 pw.println(" " + i.getKey() + ":"); 2561 for (UpdateRecord j : i.getValue()) { 2562 pw.println(" " + j + ":"); 2563 j.dump(pw, " "); 2564 } 2565 } 2566 pw.println(" Locations by Provider:"); 2567 for (Map.Entry<String, Location> i 2568 : mLocationsByProvider.entrySet()) { 2569 pw.println(" " + i.getKey() + ":"); 2570 i.getValue().dump(new PrintWriterPrinter(pw), " "); 2571 } 2572 pw.println(" Last Known Locations:"); 2573 for (Map.Entry<String, Location> i 2574 : mLastKnownLocation.entrySet()) { 2575 pw.println(" " + i.getKey() + ":"); 2576 i.getValue().dump(new PrintWriterPrinter(pw), " "); 2577 } 2578 if (mProximityAlerts.size() > 0) { 2579 pw.println(" Proximity Alerts:"); 2580 for (Map.Entry<PendingIntent, ProximityAlert> i 2581 : mProximityAlerts.entrySet()) { 2582 pw.println(" " + i.getKey() + ":"); 2583 i.getValue().dump(pw, " "); 2584 } 2585 } 2586 if (mProximitiesEntered.size() > 0) { 2587 pw.println(" Proximities Entered:"); 2588 for (ProximityAlert i : mProximitiesEntered) { 2589 pw.println(" " + i + ":"); 2590 i.dump(pw, " "); 2591 } 2592 } 2593 pw.println(" mProximityListener=" + mProximityListener); 2594 if (mEnabledProviders.size() > 0) { 2595 pw.println(" Enabled Providers:"); 2596 for (String i : mEnabledProviders) { 2597 pw.println(" " + i); 2598 } 2599 2600 } 2601 if (mDisabledProviders.size() > 0) { 2602 pw.println(" Disabled Providers:"); 2603 for (String i : mDisabledProviders) { 2604 pw.println(" " + i); 2605 } 2606 2607 } 2608 if (mMockProviders.size() > 0) { 2609 pw.println(" Mock Providers:"); 2610 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) { 2611 i.getValue().dump(pw, " "); 2612 } 2613 } 2614 pw.println(" Reported GPS UIDs @ seq " + mReportedGpsSeq + ":"); 2615 N = mReportedGpsUids.size(); 2616 for (int i=0; i<N; i++) { 2617 pw.println(" UID " + mReportedGpsUids.keyAt(i) 2618 + " seq=" + mReportedGpsUids.valueAt(i)); 2619 } 2620 } 2621 } 2622} 2623