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

Commit 98e1f384 authored by Mike Lockwood's avatar Mike Lockwood Committed by Android Git Automerger
Browse files

am aecab79b: Merge "Remove races in Geocoder/LocationProvider Proxy" into gingerbread

Merge commit 'aecab79b' into gingerbread-plus-aosp

* commit 'aecab79b':
  Remove races in Geocoder/LocationProvider Proxy
parents 2b4f1f4c aecab79b
Loading
Loading
Loading
Loading
+16 −11
Original line number Diff line number Diff line
@@ -130,6 +130,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run

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

    // wakelock variables
    private final static String WAKELOCK_KEY = "LocationManagerService";
@@ -1826,6 +1827,19 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
                            handleLocationChangedLocked(location, passive);
                        }
                    }
                } else if (msg.what == MESSAGE_PACKAGE_UPDATED) {
                    String packageName = (String) msg.obj;
                    String packageDot = packageName + ".";

                    // reconnect to external providers after their packages have been updated
                    if (mNetworkLocationProvider != null &&
                        mNetworkLocationProviderPackageName.startsWith(packageDot)) {
                        mNetworkLocationProvider.reconnect();
                    }
                    if (mGeocodeProvider != null &&
                        mGeocodeProviderPackageName.startsWith(packageDot)) {
                        mGeocodeProvider.reconnect();
                    }
                }
            } catch (Exception e) {
                // Log, don't crash!
@@ -1928,17 +1942,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
        @Override
        public void onPackageUpdateFinished(String packageName, int uid) {
            String packageDot = packageName + ".";

            // reconnect to external providers after their packages have been updated
            if (mNetworkLocationProvider != null &&
                    mNetworkLocationProviderPackageName.startsWith(packageDot)) {
                mNetworkLocationProvider.reconnect();
            }
            if (mGeocodeProvider != null &&
                    mGeocodeProviderPackageName.startsWith(packageDot)) {
                mGeocodeProvider.reconnect();
            }
            // Called by main thread; divert work to LocationWorker.
            Message.obtain(mLocationHandler, MESSAGE_PACKAGE_UPDATED, packageName).sendToTarget();
        }
    };

+23 −9
Original line number Diff line number Diff line
@@ -41,8 +41,8 @@ public class GeocoderProxy {

    private final Context mContext;
    private final Intent mIntent;
    private final Connection mServiceConnection = new Connection();
    private IGeocodeProvider mProvider;
    private final Object mMutex = new Object();  // synchronizes access to mServiceConnection
    private Connection mServiceConnection = new Connection();  // never null

    public GeocoderProxy(Context context, String serviceName) {
        mContext = context;
@@ -50,34 +50,48 @@ public class GeocoderProxy {
        mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
    }

    /**
     * When unbundled NetworkLocationService package is updated, we
     * need to unbind from the old version and re-bind to the new one.
     */
    public void reconnect() {
        synchronized (mServiceConnection) {
        synchronized (mMutex) {
            mContext.unbindService(mServiceConnection);
            mServiceConnection = new Connection();
            mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
        }
    }

    private class Connection implements ServiceConnection {

        private IGeocodeProvider mProvider;

        public void onServiceConnected(ComponentName className, IBinder service) {
            Log.d(TAG, "onServiceConnected " + className);
            synchronized (mServiceConnection) {
            synchronized (this) {
                mProvider = IGeocodeProvider.Stub.asInterface(service);
            }
        }

        public void onServiceDisconnected(ComponentName className) {
            Log.d(TAG, "onServiceDisconnected " + className);
            synchronized (mServiceConnection) {
            synchronized (this) {
                mProvider = null;
            }
        }

        public IGeocodeProvider getProvider() {
            synchronized (this) {
                return mProvider;
            }
        }
    }

    public String getFromLocation(double latitude, double longitude, int maxResults,
            GeocoderParams params, List<Address> addrs) {
        IGeocodeProvider provider;
        synchronized (mServiceConnection) {
            provider = mProvider;
        synchronized (mMutex) {
            provider = mServiceConnection.getProvider();
        }
        if (provider != null) {
            try {
@@ -95,8 +109,8 @@ public class GeocoderProxy {
            double upperRightLatitude, double upperRightLongitude, int maxResults,
            GeocoderParams params, List<Address> addrs) {
        IGeocodeProvider provider;
        synchronized (mServiceConnection) {
            provider = mProvider;
        synchronized (mMutex) {
            provider = mServiceConnection.getProvider();
        }
        if (provider != null) {
            try {
+211 −178
Original line number Diff line number Diff line
@@ -45,10 +45,10 @@ public class LocationProviderProxy implements LocationProviderInterface {

    private final Context mContext;
    private final String mName;
    private final String mServiceName;
    private ILocationProvider mProvider;
    private Handler mHandler;
    private final Connection mServiceConnection = new Connection();
    private final Intent mIntent;
    private final Handler mHandler;
    private final Object mMutex = new Object();  // synchronizes access to non-final members
    private Connection mServiceConnection = new Connection();  // never null

    // cached values set by the location manager
    private boolean mLocationTracking = false;
@@ -58,57 +58,89 @@ public class LocationProviderProxy implements LocationProviderInterface {
    private int mNetworkState;
    private NetworkInfo mNetworkInfo;

    // for caching requiresNetwork, requiresSatellite, etc.
    private DummyLocationProvider mCachedAttributes;

    // constructor for proxying location providers implemented in a separate service
    public LocationProviderProxy(Context context, String name, String serviceName,
            Handler handler) {
        mContext = context;
        mName = name;
        mServiceName = serviceName;
        mIntent = new Intent(serviceName);
        mHandler = handler;
        mContext.bindService(new Intent(serviceName), mServiceConnection, Context.BIND_AUTO_CREATE);
        mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
    }

    /**
     * When unbundled NetworkLocationService package is updated, we
     * need to unbind from the old version and re-bind to the new one.
     */
    public void reconnect() {
        synchronized (mServiceConnection) {
            // unbind first
        synchronized (mMutex) {
            mContext.unbindService(mServiceConnection);
            mContext.bindService(new Intent(mServiceName), mServiceConnection,
                Context.BIND_AUTO_CREATE);
            mServiceConnection = new Connection();
            mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
        }
    }

    private class Connection implements ServiceConnection {
    private class Connection implements ServiceConnection, Runnable {

        private ILocationProvider mProvider;

        // for caching requiresNetwork, requiresSatellite, etc.
        private DummyLocationProvider mCachedAttributes;  // synchronized by mMutex

        public void onServiceConnected(ComponentName className, IBinder service) {
            Log.d(TAG, "LocationProviderProxy.onServiceConnected " + className);
            synchronized (mServiceConnection) {
            synchronized (this) {
                mProvider = ILocationProvider.Stub.asInterface(service);
                if (mProvider != null) {
                    mHandler.post(mServiceConnectedTask);
                    mHandler.post(this);
                }
            }
        }

        public void onServiceDisconnected(ComponentName className) {
            Log.d(TAG, "LocationProviderProxy.onServiceDisconnected " + className);
            synchronized (mServiceConnection) {
            synchronized (this) {
                mProvider = null;
            }
        }

        public synchronized ILocationProvider getProvider() {
            return mProvider;
        }

        public synchronized DummyLocationProvider getCachedAttributes() {
            return mCachedAttributes;
        }

    private Runnable mServiceConnectedTask = new Runnable() {
        public void run() {
            ILocationProvider provider;
            synchronized (mServiceConnection) {
                provider = mProvider;
            synchronized (mMutex) {
                if (mServiceConnection != this) {
                    // This ServiceConnection no longer the one we want to bind to.
                    return;
                }
                ILocationProvider provider = getProvider();
                if (provider == null) {
                    return;
                }

                // resend previous values from the location manager if the service has restarted
                try {
                    if (mEnabled) {
                        provider.enable();
                    }
                    if (mLocationTracking) {
                        provider.enableLocationTracking(true);
                    }
                    if (mMinTime >= 0) {
                        provider.setMinTime(mMinTime, mMinTimeSource);
                    }
                    if (mNetworkInfo != null) {
                        provider.updateNetworkState(mNetworkState, mNetworkInfo);
                    }
                } catch (RemoteException e) {
                }

                // init cache of parameters
                if (mCachedAttributes == null) {
                    try {
                        mCachedAttributes = new DummyLocationProvider(mName, null);
@@ -125,22 +157,6 @@ public class LocationProviderProxy implements LocationProviderInterface {
                        mCachedAttributes = null;
                    }
                }

            // resend previous values from the location manager if the service has restarted
            try {
                if (mEnabled) {
                    provider.enable();
                }
                if (mLocationTracking) {
                    provider.enableLocationTracking(true);
                }
                if (mMinTime >= 0) {
                    provider.setMinTime(mMinTime, mMinTimeSource);
                }
                if (mNetworkInfo != null) {
                    provider.updateNetworkState(mNetworkState, mNetworkInfo);
                }
            } catch (RemoteException e) {
            }
        }
    };
@@ -149,81 +165,103 @@ public class LocationProviderProxy implements LocationProviderInterface {
        return mName;
    }

    private DummyLocationProvider getCachedAttributes() {
        synchronized (mMutex) {
            return mServiceConnection.getCachedAttributes();
        }
    }

    public boolean requiresNetwork() {
        if (mCachedAttributes != null) {
            return mCachedAttributes.requiresNetwork();
        DummyLocationProvider cachedAttributes = getCachedAttributes();
        if (cachedAttributes != null) {
            return cachedAttributes.requiresNetwork();
        } else {
            return false;
        }
    }

    public boolean requiresSatellite() {
        if (mCachedAttributes != null) {
            return mCachedAttributes.requiresSatellite();
        DummyLocationProvider cachedAttributes = getCachedAttributes();
        if (cachedAttributes != null) {
            return cachedAttributes.requiresSatellite();
        } else {
            return false;
        }
    }

    public boolean requiresCell() {
        if (mCachedAttributes != null) {
            return mCachedAttributes.requiresCell();
        DummyLocationProvider cachedAttributes = getCachedAttributes();
        if (cachedAttributes != null) {
            return cachedAttributes.requiresCell();
        } else {
            return false;
        }
    }

    public boolean hasMonetaryCost() {
        if (mCachedAttributes != null) {
            return mCachedAttributes.hasMonetaryCost();
        DummyLocationProvider cachedAttributes = getCachedAttributes();
        if (cachedAttributes != null) {
            return cachedAttributes.hasMonetaryCost();
        } else {
            return false;
        }
    }

    public boolean supportsAltitude() {
        if (mCachedAttributes != null) {
            return mCachedAttributes.supportsAltitude();
        DummyLocationProvider cachedAttributes = getCachedAttributes();
        if (cachedAttributes != null) {
            return cachedAttributes.supportsAltitude();
        } else {
            return false;
        }
    }

    public boolean supportsSpeed() {
        if (mCachedAttributes != null) {
            return mCachedAttributes.supportsSpeed();
        DummyLocationProvider cachedAttributes = getCachedAttributes();
        if (cachedAttributes != null) {
            return cachedAttributes.supportsSpeed();
        } else {
            return false;
        }
    }

     public boolean supportsBearing() {
        if (mCachedAttributes != null) {
            return mCachedAttributes.supportsBearing();
        DummyLocationProvider cachedAttributes = getCachedAttributes();
        if (cachedAttributes != null) {
            return cachedAttributes.supportsBearing();
        } else {
            return false;
        }
    }

    public int getPowerRequirement() {
        if (mCachedAttributes != null) {
            return mCachedAttributes.getPowerRequirement();
        DummyLocationProvider cachedAttributes = getCachedAttributes();
        if (cachedAttributes != null) {
            return cachedAttributes.getPowerRequirement();
        } else {
            return -1;
        }
    }

    public boolean meetsCriteria(Criteria criteria) {
       ILocationProvider provider;
        synchronized (mServiceConnection) {
            provider = mProvider;
    public int getAccuracy() {
        DummyLocationProvider cachedAttributes = getCachedAttributes();
        if (cachedAttributes != null) {
            return cachedAttributes.getAccuracy();
        } else {
            return -1;
        }
    }

    public boolean meetsCriteria(Criteria criteria) {
        synchronized (mMutex) {
            ILocationProvider provider = mServiceConnection.getProvider();
            if (provider != null) {
                try {
                    return provider.meetsCriteria(criteria);
                } catch (RemoteException e) {
                }
            }
        }
        // default implementation if we lost connection to the provider
        if ((criteria.getAccuracy() != Criteria.NO_REQUIREMENT) &&
            (criteria.getAccuracy() < getAccuracy())) {
@@ -246,20 +284,10 @@ public class LocationProviderProxy implements LocationProviderInterface {
        return true;
    }

    public int getAccuracy() {
        if (mCachedAttributes != null) {
            return mCachedAttributes.getAccuracy();
        } else {
            return -1;
        }
    }

    public void enable() {
        synchronized (mMutex) {
            mEnabled = true;
        ILocationProvider provider;
        synchronized (mServiceConnection) {
            provider = mProvider;
        }
            ILocationProvider provider = mServiceConnection.getProvider();
            if (provider != null) {
                try {
                    provider.enable();
@@ -267,13 +295,12 @@ public class LocationProviderProxy implements LocationProviderInterface {
                }
            }
        }
    }

    public void disable() {
        synchronized (mMutex) {
            mEnabled = false;
        ILocationProvider provider;
        synchronized (mServiceConnection) {
            provider = mProvider;
        }
            ILocationProvider provider = mServiceConnection.getProvider();
            if (provider != null) {
                try {
                    provider.disable();
@@ -281,15 +308,18 @@ public class LocationProviderProxy implements LocationProviderInterface {
                }
            }
        }
    }

    public boolean isEnabled() {
        synchronized (mMutex) {
            return mEnabled;
        }
    }

    public int getStatus(Bundle extras) {
        ILocationProvider provider;
        synchronized (mServiceConnection) {
            provider = mProvider;
        synchronized (mMutex) {
            provider = mServiceConnection.getProvider();
        }
        if (provider != null) {
            try {
@@ -302,8 +332,8 @@ public class LocationProviderProxy implements LocationProviderInterface {

    public long getStatusUpdateTime() {
        ILocationProvider provider;
        synchronized (mServiceConnection) {
            provider = mProvider;
        synchronized (mMutex) {
            provider = mServiceConnection.getProvider();
        }
        if (provider != null) {
            try {
@@ -315,28 +345,34 @@ public class LocationProviderProxy implements LocationProviderInterface {
     }

    public String getInternalState() {
        ILocationProvider provider;
        synchronized (mMutex) {
            provider = mServiceConnection.getProvider();
        }
        if (provider != null) {
            try {
            return mProvider.getInternalState();
                return provider.getInternalState();
            } catch (RemoteException e) {
                Log.e(TAG, "getInternalState failed", e);
            return null;
            }
        }
        return null;
    }

    public boolean isLocationTracking() {
        synchronized (mMutex) {
            return mLocationTracking;
        }
    }

    public void enableLocationTracking(boolean enable) {
        synchronized (mMutex) {
            mLocationTracking = enable;
            if (!enable) {
                mMinTime = -1;
                mMinTimeSource.clear();
            }
        ILocationProvider provider;
        synchronized (mServiceConnection) {
            provider = mProvider;
        }
            ILocationProvider provider = mServiceConnection.getProvider();
            if (provider != null) {
                try {
                    provider.enableLocationTracking(enable);
@@ -344,22 +380,23 @@ public class LocationProviderProxy implements LocationProviderInterface {
                }
            }
        }
    }

    public boolean requestSingleShotFix() {
        return false;
    }

    public long getMinTime() {
        synchronized (mMutex) {
            return mMinTime;
        }
    }

    public void setMinTime(long minTime, WorkSource ws) {
        synchronized (mMutex) {
            mMinTime = minTime;
            mMinTimeSource.set(ws);
        ILocationProvider provider;
        synchronized (mServiceConnection) {
            provider = mProvider;
        }
            ILocationProvider provider = mServiceConnection.getProvider();
            if (provider != null) {
                try {
                    provider.setMinTime(minTime, ws);
@@ -367,14 +404,13 @@ public class LocationProviderProxy implements LocationProviderInterface {
                }
            }
        }
    }

    public void updateNetworkState(int state, NetworkInfo info) {
        synchronized (mMutex) {
            mNetworkState = state;
            mNetworkInfo = info;
        ILocationProvider provider;
        synchronized (mServiceConnection) {
            provider = mProvider;
        }
            ILocationProvider provider = mServiceConnection.getProvider();
            if (provider != null) {
                try {
                    provider.updateNetworkState(state, info);
@@ -382,12 +418,11 @@ public class LocationProviderProxy implements LocationProviderInterface {
                }
            }
        }
    }

    public void updateLocation(Location location) {
        ILocationProvider provider;
        synchronized (mServiceConnection) {
            provider = mProvider;
        }
        synchronized (mMutex) {
            ILocationProvider provider = mServiceConnection.getProvider();
            if (provider != null) {
                try {
                    provider.updateLocation(location);
@@ -395,26 +430,24 @@ public class LocationProviderProxy implements LocationProviderInterface {
                }
            }
        }
    }

    public boolean sendExtraCommand(String command, Bundle extras) {
        ILocationProvider provider;
        synchronized (mServiceConnection) {
            provider = mProvider;
        }
        synchronized (mMutex) {
            ILocationProvider provider = mServiceConnection.getProvider();
            if (provider != null) {
                try {
                provider.sendExtraCommand(command, extras);
                    return provider.sendExtraCommand(command, extras);
                } catch (RemoteException e) {
                }
            }
        }
        return false;
    }

    public void addListener(int uid) {
        ILocationProvider provider;
        synchronized (mServiceConnection) {
            provider = mProvider;
        }
        synchronized (mMutex) {
            ILocationProvider provider = mServiceConnection.getProvider();
            if (provider != null) {
                try {
                    provider.addListener(uid);
@@ -422,12 +455,11 @@ public class LocationProviderProxy implements LocationProviderInterface {
                }
            }
        }
    }

    public void removeListener(int uid) {
        ILocationProvider provider;
        synchronized (mServiceConnection) {
            provider = mProvider;
        }
        synchronized (mMutex) {
            ILocationProvider provider = mServiceConnection.getProvider();
            if (provider != null) {
                try {
                    provider.removeListener(uid);
@@ -436,3 +468,4 @@ public class LocationProviderProxy implements LocationProviderInterface {
            }
        }
    }
}