location: Location Manager wakelock cleanup

Location Providers are now responsible for their own wakelocks and scheduling.

Also fixed a deadlock in LocationManagerService in the code for releasing
wakelocks after client notifications have been received.
The fix is to use the Receiver object and mWakeLock for synchronization
 instead of the global mLock lock.

Signed-off-by: Mike Lockwood <lockwood@android.com>
This commit is contained in:
Mike Lockwood
2009-05-07 10:12:54 -04:00
parent 90da134bef
commit 0528b9b26a
6 changed files with 86 additions and 257 deletions

View File

@@ -33,7 +33,6 @@ import java.util.Observer;
import java.util.Set;
import java.util.regex.Pattern;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentQueryMap;
@@ -132,16 +131,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
// Handler messages
private static final int MESSAGE_LOCATION_CHANGED = 1;
// Alarm manager and wakelock variables
private final static String ALARM_INTENT = "com.android.location.ALARM_INTENT";
// wakelock variables
private final static String WAKELOCK_KEY = "LocationManagerService";
private AlarmManager mAlarmManager;
private long mAlarmInterval = 0;
private PowerManager.WakeLock mWakeLock = null;
private int mPendingBroadcasts;
private long mWakeLockAcquireTime = 0;
private boolean mWakeLockGpsReceived = true;
private boolean mWakeLockNetworkReceived = true;
/**
* List of all receivers.
@@ -388,24 +381,22 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
public void onSendFinished(PendingIntent pendingIntent, Intent intent,
int resultCode, String resultData, Bundle resultExtras) {
decrementPendingBroadcasts();
}
// this must be called while synchronized by callerin a synchronized block
// containing the sending of the broadcaset
private void incrementPendingBroadcastsLocked() {
if (mPendingBroadcasts++ == 0) {
synchronized (mLock) {
LocationManagerService.this.incrementPendingBroadcastsLocked();
}
synchronized (this) {
decrementPendingBroadcastsLocked();
}
}
private void decrementPendingBroadcasts() {
synchronized (this) {
if (--mPendingBroadcasts == 0) {
LocationManagerService.this.decrementPendingBroadcasts();
}
// this must be called while synchronized by caller in a synchronized block
// containing the sending of the broadcaset
private void incrementPendingBroadcastsLocked() {
if (mPendingBroadcasts++ == 0) {
LocationManagerService.this.incrementPendingBroadcasts();
}
}
private void decrementPendingBroadcastsLocked() {
if (--mPendingBroadcasts == 0) {
LocationManagerService.this.decrementPendingBroadcasts();
}
}
}
@@ -413,7 +404,12 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
public void locationCallbackFinished(ILocationListener listener) {
Receiver receiver = getReceiver(listener);
if (receiver != null) {
receiver.decrementPendingBroadcasts();
synchronized (receiver) {
// so wakelock calls will succeed
long identity = Binder.clearCallingIdentity();
receiver.decrementPendingBroadcastsLocked();
Binder.restoreCallingIdentity(identity);
}
}
}
@@ -526,15 +522,6 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
mProvidersByName.remove(provider.getName());
}
/**
* Load providers from /data/location/<provider_name>/
* class
* kml
* nmea
* track
* location
* properties
*/
private void loadProviders() {
synchronized (mLock) {
if (sProvidersLoaded) {
@@ -585,30 +572,20 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
private void initialize() {
// Alarm manager, needs to be done before calling loadProviders() below
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
// Create a wake lock, needs to be done before calling loadProviders() below
PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
// Load providers
loadProviders();
// Register for Network (Wifi or Mobile) updates
NetworkStateBroadcastReceiver networkReceiver = new NetworkStateBroadcastReceiver();
IntentFilter networkIntentFilter = new IntentFilter();
networkIntentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
networkIntentFilter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION);
mContext.registerReceiver(networkReceiver, networkIntentFilter);
// Register for power updates
PowerStateBroadcastReceiver powerStateReceiver = new PowerStateBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ALARM_INTENT);
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
// Register for Package Manager updates
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
mContext.registerReceiver(powerStateReceiver, intentFilter);
mContext.registerReceiver(mBroadcastReceiver, intentFilter);
// listen for settings changes
ContentResolver resolver = mContext.getContentResolver();
@@ -825,12 +802,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
if (listeners > 0) {
p.setMinTime(getMinTimeLocked(provider));
p.enableLocationTracking(true);
updateWakelockStatusLocked();
}
} else {
p.enableLocationTracking(false);
p.disable();
updateWakelockStatusLocked();
}
}
@@ -1020,7 +995,6 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
long minTimeForProvider = getMinTimeLocked(provider);
proxy.setMinTime(minTimeForProvider);
proxy.enableLocationTracking(true);
updateWakelockStatusLocked();
} else {
// Notify the listener that updates are currently disabled
receiver.callProviderEnabledLocked(provider, false);
@@ -1109,8 +1083,6 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
}
}
updateWakelockStatusLocked();
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -1258,13 +1230,13 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
Intent enteredIntent = new Intent();
enteredIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true);
try {
synchronized (mLock) {
// synchronize to ensure incrementPendingBroadcastsLocked()
synchronized (this) {
// synchronize to ensure incrementPendingBroadcasts()
// is called before decrementPendingBroadcasts()
intent.send(mContext, 0, enteredIntent, this, mLocationHandler);
// call this after broadcasting so we do not increment
// if we throw an exeption.
incrementPendingBroadcastsLocked();
incrementPendingBroadcasts();
}
} catch (PendingIntent.CanceledException e) {
if (LOCAL_LOGV) {
@@ -1283,13 +1255,13 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
Intent exitedIntent = new Intent();
exitedIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false);
try {
synchronized (mLock) {
// synchronize to ensure incrementPendingBroadcastsLocked()
synchronized (this) {
// synchronize to ensure incrementPendingBroadcasts()
// is called before decrementPendingBroadcasts()
intent.send(mContext, 0, exitedIntent, this, mLocationHandler);
// call this after broadcasting so we do not increment
// if we throw an exeption.
incrementPendingBroadcastsLocked();
incrementPendingBroadcasts();
}
} catch (PendingIntent.CanceledException e) {
if (LOCAL_LOGV) {
@@ -1346,7 +1318,11 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
public void onSendFinished(PendingIntent pendingIntent, Intent intent,
int resultCode, String resultData, Bundle resultExtras) {
decrementPendingBroadcasts();
// synchronize to ensure incrementPendingBroadcasts()
// is called before decrementPendingBroadcasts()
synchronized (this) {
decrementPendingBroadcasts();
}
}
}
@@ -1581,11 +1557,6 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
writeLastKnownLocationLocked(provider, location);
if (LocationManager.NETWORK_PROVIDER.equals(p.getName())) {
mWakeLockNetworkReceived = true;
}
// Gps location received signal is in NetworkStateBroadcastReceiver
// Fetch latest status update time
long newStatusUpdateTime = p.getStatusUpdateTime();
@@ -1668,7 +1639,6 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
handleLocationChangedLocked(location);
updateWakelockStatusLocked();
}
}
} catch (Exception e) {
@@ -1678,20 +1648,12 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
}
private class PowerStateBroadcastReceiver extends BroadcastReceiver {
@Override public void onReceive(Context context, Intent intent) {
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(ALARM_INTENT)) {
synchronized (mLock) {
log("PowerStateBroadcastReceiver: Alarm received");
// Have to do this immediately, rather than posting a
// message, so we execute our code while the system
// is holding a wake lock until the alarm broadcast
// is finished.
acquireWakeLockLocked();
}
} else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
|| action.equals(Intent.ACTION_PACKAGE_RESTARTED)) {
synchronized (mLock) {
int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
@@ -1733,15 +1695,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
}
}
}
}
}
private class NetworkStateBroadcastReceiver extends BroadcastReceiver {
@Override public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
} else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
boolean noConnectivity =
intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
if (!noConnectivity) {
@@ -1759,146 +1713,43 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
}
}
} else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION)) {
final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED,
false);
synchronized (mLock) {
if (!enabled) {
// When GPS is disabled, we are OK to release wake-lock
mWakeLockGpsReceived = true;
}
}
}
}
}
};
// Wake locks
private void updateWakelockStatusLocked() {
log("updateWakelockStatus()");
long callerId = Binder.clearCallingIdentity();
boolean needsLock = (mPendingBroadcasts > 0);
long minTime = Integer.MAX_VALUE;
if (mNetworkLocationProvider != null && mNetworkLocationProvider.isLocationTracking()) {
needsLock = true;
minTime = Math.min(mNetworkLocationProvider.getMinTime(), minTime);
}
if (mGpsLocationProvider != null && mGpsLocationProvider.isLocationTracking()) {
needsLock = true;
minTime = Math.min(mGpsLocationProvider.getMinTime(), minTime);
}
PendingIntent sender =
PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_INTENT), 0);
// Cancel existing alarm
log("Cancelling existing alarm");
mAlarmManager.cancel(sender);
if (needsLock) {
long now = SystemClock.elapsedRealtime();
mAlarmManager.set(
AlarmManager.ELAPSED_REALTIME_WAKEUP, now + minTime, sender);
mAlarmInterval = minTime;
log("Creating a new wakelock alarm with minTime = " + minTime);
} else {
log("No need for alarm");
mAlarmInterval = -1;
releaseWakeLockLocked();
}
Binder.restoreCallingIdentity(callerId);
}
private void acquireWakeLockLocked() {
try {
acquireWakeLockXLocked();
} catch (Exception e) {
// This is to catch a runtime exception thrown when we try to release an
// already released lock.
Log.e(TAG, "exception in acquireWakeLock()", e);
}
}
private void acquireWakeLockXLocked() {
if (mWakeLock.isHeld()) {
log("Must release wakelock before acquiring");
mWakeLockAcquireTime = 0;
mWakeLock.release();
}
boolean networkActive = (mNetworkLocationProvider != null)
&& mNetworkLocationProvider.isLocationTracking();
boolean gpsActive = (mGpsLocationProvider != null)
&& mGpsLocationProvider.isLocationTracking();
boolean needsLock = networkActive || gpsActive;
if (!needsLock) {
log("No need for Lock!");
return;
}
mWakeLockGpsReceived = !gpsActive;
mWakeLockNetworkReceived = !networkActive;
// Acquire wake lock
mWakeLock.acquire();
mWakeLockAcquireTime = SystemClock.elapsedRealtime();
log("Acquired wakelock");
if (mNetworkLocationProvider != null) {
mNetworkLocationProvider.wakeLockAcquired();
}
if (mGpsLocationProvider != null) {
mGpsLocationProvider.wakeLockAcquired();
}
}
private void releaseWakeLockLocked() {
try {
releaseWakeLockXLocked();
} catch (Exception e) {
// This is to catch a runtime exception thrown when we try to release an
// already released lock.
Log.e(TAG, "exception in releaseWakeLock()", e);
}
}
private void releaseWakeLockXLocked() {
if (mNetworkLocationProvider != null) {
mNetworkLocationProvider.wakeLockReleased();
}
if (mGpsLocationProvider != null) {
mGpsLocationProvider.wakeLockReleased();
}
// Release wake lock
mWakeLockAcquireTime = 0;
if (mWakeLock.isHeld()) {
log("Released wakelock");
mWakeLock.release();
} else {
log("Can't release wakelock again!");
}
}
private void incrementPendingBroadcastsLocked() {
if (mPendingBroadcasts++ == 0) {
updateWakelockStatusLocked();
private void incrementPendingBroadcasts() {
synchronized (mWakeLock) {
if (mPendingBroadcasts++ == 0) {
try {
mWakeLock.acquire();
log("Acquired wakelock");
} catch (Exception e) {
// This is to catch a runtime exception thrown when we try to release an
// already released lock.
Log.e(TAG, "exception in acquireWakeLock()", e);
}
}
}
}
private void decrementPendingBroadcasts() {
synchronized (mLock) {
synchronized (mWakeLock) {
if (--mPendingBroadcasts == 0) {
updateWakelockStatusLocked();
try {
// Release wake lock
if (mWakeLock.isHeld()) {
mWakeLock.release();
log("Released wakelock");
} else {
log("Can't release wakelock again!");
}
} catch (Exception e) {
// This is to catch a runtime exception thrown when we try to release an
// already released lock.
Log.e(TAG, "exception in releaseWakeLock()", e);
}
}
}
}
@@ -2069,7 +1920,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump AlarmManager from from pid="
pw.println("Permission Denial: can't dump LocationManagerService from from pid="
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid());
return;
@@ -2081,10 +1932,6 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
pw.println(" mGpsLocationProvider=" + mGpsLocationProvider);
pw.println(" mNetworkLocationProvider=" + mNetworkLocationProvider);
pw.println(" mCollector=" + mCollector);
pw.println(" mAlarmInterval=" + mAlarmInterval
+ " mWakeLockAcquireTime=" + mWakeLockAcquireTime);
pw.println(" mWakeLockGpsReceived=" + mWakeLockGpsReceived
+ " mWakeLockNetworkReceived=" + mWakeLockNetworkReceived);
pw.println(" Listeners:");
int N = mReceivers.size();
for (int i=0; i<N; i++) {