Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 48f17518 authored by Mike Lockwood's avatar Mike Lockwood
Browse files

location: Location Manager wakelock cleanup, phase 2



Remove two second timeout for wakelock when broadcasting events to
location listeners. Instead, hold wakelock until receipt of the event
is acknowledged, either via a Binder call or the
PendingIntent.OnFinished interface.

Signed-off-by: default avatarMike Lockwood <lockwood@android.com>
parent 0a57e5b7
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -46,6 +46,9 @@ interface ILocationManager
    boolean addGpsStatusListener(IGpsStatusListener listener);
    void removeGpsStatusListener(IGpsStatusListener listener);

    // for reporting callback completion
    void locationCallbackFinished(ILocationListener listener);

    boolean sendExtraCommand(String provider, String command, inout Bundle extras);

    void addProximityAlert(double latitude, double longitude, float distance,
+5 −0
Original line number Diff line number Diff line
@@ -194,6 +194,11 @@ public class LocationManager {
                    mListener.onProviderDisabled((String) msg.obj);
                    break;
            }
            try {
                mService.locationCallbackFinished(this);
            } catch (RemoteException e) {
                Log.e(TAG, "locationCallbackFinished: RemoteException", e);
            }
        }
    }
    /**
+167 −81
Original line number Diff line number Diff line
@@ -93,10 +93,6 @@ public class LocationManagerService extends ILocationManager.Stub {
    // Max time to hold wake lock for, in milliseconds.
    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.
    private HashMap<String,Long> mLastWriteTime = new HashMap<String,Long>();

@@ -130,7 +126,6 @@ public class LocationManagerService extends ILocationManager.Stub {

    // Handler messages
    private static final int MESSAGE_LOCATION_CHANGED = 1;
    private static final int MESSAGE_RELEASE_WAKE_LOCK = 2;

    // Alarm manager and wakelock variables
    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 long mAlarmInterval = 0;
    private PowerManager.WakeLock mWakeLock = null;
    private int mPendingBroadcasts;
    private long mWakeLockAcquireTime = 0;
    private boolean mWakeLockGpsReceived = true;
    private boolean mWakeLockNetworkReceived = true;
@@ -159,7 +155,8 @@ public class LocationManagerService extends ILocationManager.Stub {
        new HashMap<String,ArrayList<UpdateRecord>>();

    // Proximity listeners
    private Receiver mProximityListener = null;
    private Receiver mProximityReceiver = null;
    private ILocationListener mProximityListener = null;
    private HashMap<PendingIntent,ProximityAlert> mProximityAlerts =
        new HashMap<PendingIntent,ProximityAlert>();
    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
     * location updates.
     */
    private final class Receiver implements IBinder.DeathRecipient {
    private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
        final ILocationListener mListener;
        final PendingIntent mPendingIntent;
        final Object mKey;
        final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
        int mPendingBroadcasts;

        Receiver(ILocationListener listener) {
            mListener = listener;
@@ -252,7 +250,16 @@ public class LocationManagerService extends ILocationManager.Stub {
        public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
            if (mListener != null) {
                try {
                    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) {
                    return false;
                }
@@ -261,7 +268,14 @@ public class LocationManagerService extends ILocationManager.Stub {
                statusChanged.putExtras(extras);
                statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
                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) {
                    return false;
                }
@@ -272,7 +286,16 @@ public class LocationManagerService extends ILocationManager.Stub {
        public boolean callLocationChangedLocked(Location location) {
            if (mListener != null) {
                try {
                    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) {
                    return false;
                }
@@ -280,7 +303,53 @@ public class LocationManagerService extends ILocationManager.Stub {
                Intent locationChanged = new Intent();
                locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
                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) {
                    return false;
                }
@@ -295,6 +364,42 @@ public class LocationManagerService extends ILocationManager.Stub {
            synchronized (mLock) {
                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,30 +827,12 @@ public class LocationManagerService extends ILocationManager.Stub {
            for (int i=0; i<N; i++) {
                UpdateRecord record = records.get(i);
                // Sends a notification message to the receiver
                try {
                    Receiver receiver = record.mReceiver;
                    if (receiver.isListener()) {
                        if (enabled) {
                            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 (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
                    if (deadReceivers == null) {
                        deadReceivers = new ArrayList<Receiver>();
                                deadReceivers.add(receiver);
                            }
                        deadReceivers.add(record.mReceiver);
                    }
                }
                } catch (RemoteException e) {
                    // The death link will clean this up.
                }
                listeners++;
            }
        }
@@ -958,15 +1045,8 @@ public class LocationManagerService extends ILocationManager.Stub {
                impl.enableLocationTracking(true);
                updateWakelockStatusLocked();
            } else {
                try {
                // Notify the listener that updates are currently disabled
                    if (receiver.isListener()) {
                        receiver.getListener().onProviderDisabled(provider);
                    }
                } catch(RemoteException e) {
                    Log.w(TAG, "RemoteException calling onProviderDisabled on " +
                            receiver.getListener());
                }
                receiver.callProviderEnabledLocked(provider, false);
            }
        } finally {
            Binder.restoreCallingIdentity(identity);
@@ -1161,7 +1241,7 @@ public class LocationManagerService extends ILocationManager.Stub {
    }

    // Listener for receiving locations to trigger proximity alerts
    class ProximityListener extends ILocationListener.Stub {
    class ProximityListener extends ILocationListener.Stub implements PendingIntent.OnFinished {

        boolean isGpsAvailable = false;

@@ -1198,7 +1278,14 @@ public class LocationManagerService extends ILocationManager.Stub {
                        Intent enteredIntent = new Intent();
                        enteredIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true);
                        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) {
                            if (LOCAL_LOGV) {
                                Log.v(TAG, "Canceled proximity alert: " + alert, e);
@@ -1216,7 +1303,14 @@ public class LocationManagerService extends ILocationManager.Stub {
                        Intent exitedIntent = new Intent();
                        exitedIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false);
                        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) {
                            if (LOCAL_LOGV) {
                                Log.v(TAG, "Canceled proximity alert: " + alert, e);
@@ -1269,6 +1363,11 @@ public class LocationManagerService extends ILocationManager.Stub {
                isGpsAvailable = false;
            }
        }

        public void onSendFinished(PendingIntent pendingIntent, Intent intent,
                int resultCode, String resultData, Bundle resultExtras) {
            decrementPendingBroadcasts();
        }
    }

    public void addProximityAlert(double latitude, double longitude,
@@ -1306,19 +1405,20 @@ public class LocationManagerService extends ILocationManager.Stub {
                latitude, longitude, radius, expiration, intent);
        mProximityAlerts.put(intent, alert);

        if (mProximityListener == null) {
            mProximityListener = new Receiver(new ProximityListener());
        if (mProximityReceiver == null) {
            mProximityListener = new ProximityListener();
            mProximityReceiver = new Receiver(mProximityListener);

            LocationProvider provider = LocationProviderImpl.getProvider(
                LocationManager.GPS_PROVIDER);
            if (provider != null) {
                requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityListener);
                requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityReceiver);
            }

            provider =
                LocationProviderImpl.getProvider(LocationManager.NETWORK_PROVIDER);
            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);
        if (mProximityAlerts.size() == 0) {
            removeUpdatesLocked(mProximityListener);
            removeUpdatesLocked(mProximityReceiver);
            mProximityReceiver = null;
            mProximityListener = null;
        }
     }
@@ -1585,35 +1686,7 @@ public class LocationManagerService extends ILocationManager.Stub {
                        }

                        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();
                        releaseWakeLockLocked();
                    }
                }
            } catch (Exception e) {
@@ -1727,7 +1800,7 @@ public class LocationManagerService extends ILocationManager.Stub {

        long callerId = Binder.clearCallingIdentity();
        
        boolean needsLock = false;
        boolean needsLock = (mPendingBroadcasts > 0);
        long minTime = Integer.MAX_VALUE;

        if (mNetworkLocationProvider != null && mNetworkLocationProvider.isLocationTracking()) {
@@ -1757,8 +1830,6 @@ public class LocationManagerService extends ILocationManager.Stub {
            log("No need for alarm");
            mAlarmInterval = -1;

            // Clear out existing wakelocks
            mLocationHandler.removeMessages(MESSAGE_RELEASE_WAKE_LOCK);
            releaseWakeLockLocked();
        }
        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

    public String getFromLocation(double latitude, double longitude, int maxResults,
@@ -2061,6 +2146,7 @@ public class LocationManagerService extends ILocationManager.Stub {
                    i.dump(pw, "      ");
                }
            }
            pw.println("  mProximityReceiver=" + mProximityReceiver);
            pw.println("  mProximityListener=" + mProximityListener);
            if (mEnabledProviders.size() > 0) {
                pw.println("  Enabled Providers:");