Merge change 482 into donut

* changes:
  location: Location Manager wakelock cleanup, phase 2
This commit is contained in:
Android (Google) Code Review
2009-04-23 22:44:05 -07:00
3 changed files with 176 additions and 82 deletions

View File

@@ -45,7 +45,10 @@ interface ILocationManager
boolean addGpsStatusListener(IGpsStatusListener listener); boolean addGpsStatusListener(IGpsStatusListener listener);
void removeGpsStatusListener(IGpsStatusListener listener); void removeGpsStatusListener(IGpsStatusListener listener);
// for reporting callback completion
void locationCallbackFinished(ILocationListener listener);
boolean sendExtraCommand(String provider, String command, inout Bundle extras); boolean sendExtraCommand(String provider, String command, inout Bundle extras);
void addProximityAlert(double latitude, double longitude, float distance, void addProximityAlert(double latitude, double longitude, float distance,

View File

@@ -194,6 +194,11 @@ public class LocationManager {
mListener.onProviderDisabled((String) msg.obj); mListener.onProviderDisabled((String) msg.obj);
break; break;
} }
try {
mService.locationCallbackFinished(this);
} catch (RemoteException e) {
Log.e(TAG, "locationCallbackFinished: RemoteException", e);
}
} }
} }
/** /**

View File

@@ -93,10 +93,6 @@ public class LocationManagerService extends ILocationManager.Stub {
// Max time to hold wake lock for, in milliseconds. // Max time to hold wake lock for, in milliseconds.
private static final long MAX_TIME_FOR_WAKE_LOCK = 60 * 1000L; private static final long MAX_TIME_FOR_WAKE_LOCK = 60 * 1000L;
// Time to wait after releasing a wake lock for clients to process location update,
// in milliseconds.
private static final long TIME_AFTER_WAKE_LOCK = 2 * 1000L;
// The last time a location was written, by provider name. // The last time a location was written, by provider name.
private HashMap<String,Long> mLastWriteTime = new HashMap<String,Long>(); private HashMap<String,Long> mLastWriteTime = new HashMap<String,Long>();
@@ -130,7 +126,6 @@ public class LocationManagerService extends ILocationManager.Stub {
// Handler messages // Handler messages
private static final int MESSAGE_LOCATION_CHANGED = 1; private static final int MESSAGE_LOCATION_CHANGED = 1;
private static final int MESSAGE_RELEASE_WAKE_LOCK = 2;
// Alarm manager and wakelock variables // Alarm manager and wakelock variables
private final static String ALARM_INTENT = "com.android.location.ALARM_INTENT"; private final static String ALARM_INTENT = "com.android.location.ALARM_INTENT";
@@ -138,6 +133,7 @@ public class LocationManagerService extends ILocationManager.Stub {
private AlarmManager mAlarmManager; private AlarmManager mAlarmManager;
private long mAlarmInterval = 0; private long mAlarmInterval = 0;
private PowerManager.WakeLock mWakeLock = null; private PowerManager.WakeLock mWakeLock = null;
private int mPendingBroadcasts;
private long mWakeLockAcquireTime = 0; private long mWakeLockAcquireTime = 0;
private boolean mWakeLockGpsReceived = true; private boolean mWakeLockGpsReceived = true;
private boolean mWakeLockNetworkReceived = true; private boolean mWakeLockNetworkReceived = true;
@@ -159,7 +155,8 @@ public class LocationManagerService extends ILocationManager.Stub {
new HashMap<String,ArrayList<UpdateRecord>>(); new HashMap<String,ArrayList<UpdateRecord>>();
// Proximity listeners // Proximity listeners
private Receiver mProximityListener = null; private Receiver mProximityReceiver = null;
private ILocationListener mProximityListener = null;
private HashMap<PendingIntent,ProximityAlert> mProximityAlerts = private HashMap<PendingIntent,ProximityAlert> mProximityAlerts =
new HashMap<PendingIntent,ProximityAlert>(); new HashMap<PendingIntent,ProximityAlert>();
private HashSet<ProximityAlert> mProximitiesEntered = private HashSet<ProximityAlert> mProximitiesEntered =
@@ -181,11 +178,12 @@ public class LocationManagerService extends ILocationManager.Stub {
* A wrapper class holding either an ILocationListener or a PendingIntent to receive * A wrapper class holding either an ILocationListener or a PendingIntent to receive
* location updates. * location updates.
*/ */
private final class Receiver implements IBinder.DeathRecipient { private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
final ILocationListener mListener; final ILocationListener mListener;
final PendingIntent mPendingIntent; final PendingIntent mPendingIntent;
final Object mKey; final Object mKey;
final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>(); final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
int mPendingBroadcasts;
Receiver(ILocationListener listener) { Receiver(ILocationListener listener) {
mListener = listener; mListener = listener;
@@ -252,7 +250,16 @@ public class LocationManagerService extends ILocationManager.Stub {
public boolean callStatusChangedLocked(String provider, int status, Bundle extras) { public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
if (mListener != null) { if (mListener != null) {
try { try {
mListener.onStatusChanged(provider, status, extras); synchronized (this) {
// synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts()
mListener.onStatusChanged(provider, status, extras);
if (mListener != mProximityListener) {
// call this after broadcasting so we do not increment
// if we throw an exeption.
incrementPendingBroadcastsLocked();
}
}
} catch (RemoteException e) { } catch (RemoteException e) {
return false; return false;
} }
@@ -261,7 +268,14 @@ public class LocationManagerService extends ILocationManager.Stub {
statusChanged.putExtras(extras); statusChanged.putExtras(extras);
statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status); statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
try { try {
mPendingIntent.send(mContext, 0, statusChanged, null, null); synchronized (this) {
// synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts()
mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler);
// call this after broadcasting so we do not increment
// if we throw an exeption.
incrementPendingBroadcastsLocked();
}
} catch (PendingIntent.CanceledException e) { } catch (PendingIntent.CanceledException e) {
return false; return false;
} }
@@ -272,7 +286,16 @@ public class LocationManagerService extends ILocationManager.Stub {
public boolean callLocationChangedLocked(Location location) { public boolean callLocationChangedLocked(Location location) {
if (mListener != null) { if (mListener != null) {
try { try {
mListener.onLocationChanged(location); synchronized (this) {
// synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts()
mListener.onLocationChanged(location);
if (mListener != mProximityListener) {
// call this after broadcasting so we do not increment
// if we throw an exeption.
incrementPendingBroadcastsLocked();
}
}
} catch (RemoteException e) { } catch (RemoteException e) {
return false; return false;
} }
@@ -280,7 +303,53 @@ public class LocationManagerService extends ILocationManager.Stub {
Intent locationChanged = new Intent(); Intent locationChanged = new Intent();
locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location); locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
try { try {
mPendingIntent.send(mContext, 0, locationChanged, null, null); synchronized (this) {
// synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts()
mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler);
// call this after broadcasting so we do not increment
// if we throw an exeption.
incrementPendingBroadcastsLocked();
}
} catch (PendingIntent.CanceledException e) {
return false;
}
}
return true;
}
public boolean callProviderEnabledLocked(String provider, boolean enabled) {
if (mListener != null) {
try {
synchronized (this) {
// synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts()
if (enabled) {
mListener.onProviderEnabled(provider);
} else {
mListener.onProviderDisabled(provider);
}
if (mListener != mProximityListener) {
// call this after broadcasting so we do not increment
// if we throw an exeption.
incrementPendingBroadcastsLocked();
}
}
} catch (RemoteException e) {
return false;
}
} else {
Intent providerIntent = new Intent();
providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
try {
synchronized (this) {
// synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts()
mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler);
// call this after broadcasting so we do not increment
// if we throw an exeption.
incrementPendingBroadcastsLocked();
}
} catch (PendingIntent.CanceledException e) { } catch (PendingIntent.CanceledException e) {
return false; return false;
} }
@@ -295,6 +364,42 @@ public class LocationManagerService extends ILocationManager.Stub {
synchronized (mLock) { synchronized (mLock) {
removeUpdatesLocked(this); removeUpdatesLocked(this);
} }
synchronized (this) {
if (mPendingBroadcasts > 0) {
LocationManagerService.this.decrementPendingBroadcasts();
mPendingBroadcasts = 0;
}
}
}
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();
}
}
}
private void decrementPendingBroadcasts() {
synchronized (this) {
if (--mPendingBroadcasts == 0) {
LocationManagerService.this.decrementPendingBroadcasts();
}
}
}
}
public void locationCallbackFinished(ILocationListener listener) {
Receiver receiver = getReceiver(listener);
if (receiver != null) {
receiver.decrementPendingBroadcasts();
} }
} }
@@ -722,29 +827,11 @@ public class LocationManagerService extends ILocationManager.Stub {
for (int i=0; i<N; i++) { for (int i=0; i<N; i++) {
UpdateRecord record = records.get(i); UpdateRecord record = records.get(i);
// Sends a notification message to the receiver // Sends a notification message to the receiver
try { if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
Receiver receiver = record.mReceiver; if (deadReceivers == null) {
if (receiver.isListener()) { deadReceivers = new ArrayList<Receiver>();
if (enabled) { deadReceivers.add(record.mReceiver);
receiver.getListener().onProviderEnabled(provider);
} else {
receiver.getListener().onProviderDisabled(provider);
}
} else {
Intent providerIntent = new Intent();
providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
try {
receiver.getPendingIntent().send(mContext, 0,
providerIntent, null, null);
} catch (PendingIntent.CanceledException e) {
if (deadReceivers == null) {
deadReceivers = new ArrayList<Receiver>();
deadReceivers.add(receiver);
}
}
} }
} catch (RemoteException e) {
// The death link will clean this up.
} }
listeners++; listeners++;
} }
@@ -958,15 +1045,8 @@ public class LocationManagerService extends ILocationManager.Stub {
impl.enableLocationTracking(true); impl.enableLocationTracking(true);
updateWakelockStatusLocked(); updateWakelockStatusLocked();
} else { } else {
try { // Notify the listener that updates are currently disabled
// Notify the listener that updates are currently disabled receiver.callProviderEnabledLocked(provider, false);
if (receiver.isListener()) {
receiver.getListener().onProviderDisabled(provider);
}
} catch(RemoteException e) {
Log.w(TAG, "RemoteException calling onProviderDisabled on " +
receiver.getListener());
}
} }
} finally { } finally {
Binder.restoreCallingIdentity(identity); Binder.restoreCallingIdentity(identity);
@@ -1161,7 +1241,7 @@ public class LocationManagerService extends ILocationManager.Stub {
} }
// Listener for receiving locations to trigger proximity alerts // Listener for receiving locations to trigger proximity alerts
class ProximityListener extends ILocationListener.Stub { class ProximityListener extends ILocationListener.Stub implements PendingIntent.OnFinished {
boolean isGpsAvailable = false; boolean isGpsAvailable = false;
@@ -1198,7 +1278,14 @@ public class LocationManagerService extends ILocationManager.Stub {
Intent enteredIntent = new Intent(); Intent enteredIntent = new Intent();
enteredIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true); enteredIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true);
try { try {
intent.send(mContext, 0, enteredIntent, null, null); synchronized (mLock) {
// synchronize to ensure incrementPendingBroadcastsLocked()
// 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();
}
} catch (PendingIntent.CanceledException e) { } catch (PendingIntent.CanceledException e) {
if (LOCAL_LOGV) { if (LOCAL_LOGV) {
Log.v(TAG, "Canceled proximity alert: " + alert, e); Log.v(TAG, "Canceled proximity alert: " + alert, e);
@@ -1216,7 +1303,14 @@ public class LocationManagerService extends ILocationManager.Stub {
Intent exitedIntent = new Intent(); Intent exitedIntent = new Intent();
exitedIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false); exitedIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false);
try { try {
intent.send(mContext, 0, exitedIntent, null, null); synchronized (mLock) {
// synchronize to ensure incrementPendingBroadcastsLocked()
// 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();
}
} catch (PendingIntent.CanceledException e) { } catch (PendingIntent.CanceledException e) {
if (LOCAL_LOGV) { if (LOCAL_LOGV) {
Log.v(TAG, "Canceled proximity alert: " + alert, e); Log.v(TAG, "Canceled proximity alert: " + alert, e);
@@ -1269,6 +1363,11 @@ public class LocationManagerService extends ILocationManager.Stub {
isGpsAvailable = false; isGpsAvailable = false;
} }
} }
public void onSendFinished(PendingIntent pendingIntent, Intent intent,
int resultCode, String resultData, Bundle resultExtras) {
decrementPendingBroadcasts();
}
} }
public void addProximityAlert(double latitude, double longitude, public void addProximityAlert(double latitude, double longitude,
@@ -1306,19 +1405,20 @@ public class LocationManagerService extends ILocationManager.Stub {
latitude, longitude, radius, expiration, intent); latitude, longitude, radius, expiration, intent);
mProximityAlerts.put(intent, alert); mProximityAlerts.put(intent, alert);
if (mProximityListener == null) { if (mProximityReceiver == null) {
mProximityListener = new Receiver(new ProximityListener()); mProximityListener = new ProximityListener();
mProximityReceiver = new Receiver(mProximityListener);
LocationProvider provider = LocationProviderImpl.getProvider( LocationProvider provider = LocationProviderImpl.getProvider(
LocationManager.GPS_PROVIDER); LocationManager.GPS_PROVIDER);
if (provider != null) { if (provider != null) {
requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityListener); requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityReceiver);
} }
provider = provider =
LocationProviderImpl.getProvider(LocationManager.NETWORK_PROVIDER); LocationProviderImpl.getProvider(LocationManager.NETWORK_PROVIDER);
if (provider != null) { if (provider != null) {
requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityListener); requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityReceiver);
} }
} }
} }
@@ -1342,7 +1442,8 @@ public class LocationManagerService extends ILocationManager.Stub {
mProximityAlerts.remove(intent); mProximityAlerts.remove(intent);
if (mProximityAlerts.size() == 0) { if (mProximityAlerts.size() == 0) {
removeUpdatesLocked(mProximityListener); removeUpdatesLocked(mProximityReceiver);
mProximityReceiver = null;
mProximityListener = null; mProximityListener = null;
} }
} }
@@ -1585,35 +1686,7 @@ public class LocationManagerService extends ILocationManager.Stub {
} }
handleLocationChangedLocked(location); handleLocationChangedLocked(location);
if ((mWakeLockAcquireTime != 0) &&
(SystemClock.elapsedRealtime() - mWakeLockAcquireTime
> MAX_TIME_FOR_WAKE_LOCK)) {
removeMessages(MESSAGE_RELEASE_WAKE_LOCK);
log("LocationWorkerHandler: Exceeded max time for wake lock");
Message m = Message.obtain(this, MESSAGE_RELEASE_WAKE_LOCK);
sendMessageAtFrontOfQueue(m);
} else if (mWakeLockAcquireTime != 0 &&
mWakeLockGpsReceived && mWakeLockNetworkReceived) {
removeMessages(MESSAGE_RELEASE_WAKE_LOCK);
log("LocationWorkerHandler: Locations received.");
mWakeLockAcquireTime = 0;
Message m = Message.obtain(this, MESSAGE_RELEASE_WAKE_LOCK);
sendMessageDelayed(m, TIME_AFTER_WAKE_LOCK);
}
}
} else if (msg.what == MESSAGE_RELEASE_WAKE_LOCK) {
log("LocationWorkerHandler: Release");
// Update wakelock status so the next alarm is set before releasing wakelock
synchronized (mLock) {
updateWakelockStatusLocked(); updateWakelockStatusLocked();
releaseWakeLockLocked();
} }
} }
} catch (Exception e) { } catch (Exception e) {
@@ -1727,7 +1800,7 @@ public class LocationManagerService extends ILocationManager.Stub {
long callerId = Binder.clearCallingIdentity(); long callerId = Binder.clearCallingIdentity();
boolean needsLock = false; boolean needsLock = (mPendingBroadcasts > 0);
long minTime = Integer.MAX_VALUE; long minTime = Integer.MAX_VALUE;
if (mNetworkLocationProvider != null && mNetworkLocationProvider.isLocationTracking()) { if (mNetworkLocationProvider != null && mNetworkLocationProvider.isLocationTracking()) {
@@ -1757,8 +1830,6 @@ public class LocationManagerService extends ILocationManager.Stub {
log("No need for alarm"); log("No need for alarm");
mAlarmInterval = -1; mAlarmInterval = -1;
// Clear out existing wakelocks
mLocationHandler.removeMessages(MESSAGE_RELEASE_WAKE_LOCK);
releaseWakeLockLocked(); releaseWakeLockLocked();
} }
Binder.restoreCallingIdentity(callerId); Binder.restoreCallingIdentity(callerId);
@@ -1836,6 +1907,20 @@ public class LocationManagerService extends ILocationManager.Stub {
} }
} }
private void incrementPendingBroadcastsLocked() {
if (mPendingBroadcasts++ == 0) {
updateWakelockStatusLocked();
}
}
private void decrementPendingBroadcasts() {
synchronized (mLock) {
if (--mPendingBroadcasts == 0) {
updateWakelockStatusLocked();
}
}
}
// Geocoder // Geocoder
public String getFromLocation(double latitude, double longitude, int maxResults, public String getFromLocation(double latitude, double longitude, int maxResults,
@@ -2061,6 +2146,7 @@ public class LocationManagerService extends ILocationManager.Stub {
i.dump(pw, " "); i.dump(pw, " ");
} }
} }
pw.println(" mProximityReceiver=" + mProximityReceiver);
pw.println(" mProximityListener=" + mProximityListener); pw.println(" mProximityListener=" + mProximityListener);
if (mEnabledProviders.size() > 0) { if (mEnabledProviders.size() > 0) {
pw.println(" Enabled Providers:"); pw.println(" Enabled Providers:");