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