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

Commit 42cc63d1 authored by Nick Pelly's avatar Nick Pelly Committed by Android Git Automerger
Browse files

am 96e4ae6c: am 82b3b1bc: Merge "Make location providers upgradeable." into jb-dev

* commit '96e4ae6c':
  Make location providers upgradeable.
parents 1532f46f 96e4ae6c
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -582,11 +582,11 @@
    <!-- True if WallpaperService is enabled -->
    <bool name="config_enableWallpaperService">true</bool>

    <!-- Component name of the service providing network location support. -->
    <string name="config_networkLocationProvider" translatable="false">@null</string>
    <!-- Package name providing network location support. -->
    <string name="config_networkLocationProviderPackageName" translatable="false">@null</string>

    <!-- Component name of the service providing geocoder API support. -->
    <string name="config_geocodeProvider" translatable="false">@null</string>
    <!-- Package name providing geocoder API support. -->
    <string name="config_geocodeProviderPackageName" translatable="false">@null</string>

    <!-- Boolean indicating if current platform supports bluetooth SCO for off call
    use cases -->
+2 −2
Original line number Diff line number Diff line
@@ -1461,8 +1461,8 @@
  <java-symbol type="string" name="car_mode_disable_notification_title" />
  <java-symbol type="string" name="chooser_wallpaper" />
  <java-symbol type="string" name="config_datause_iface" />
  <java-symbol type="string" name="config_geocodeProvider" />
  <java-symbol type="string" name="config_networkLocationProvider" />
  <java-symbol type="string" name="config_geocodeProviderPackageName" />
  <java-symbol type="string" name="config_networkLocationProviderPackageName" />
  <java-symbol type="string" name="config_wimaxManagerClassname" />
  <java-symbol type="string" name="config_wimaxNativeLibLocation" />
  <java-symbol type="string" name="config_wimaxServiceClassname" />
+108 −25
Original line number Diff line number Diff line
@@ -26,7 +26,11 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
import android.content.res.Resources;
import android.database.Cursor;
import android.location.Address;
@@ -123,8 +127,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
    private static boolean sProvidersLoaded = false;

    private final Context mContext;
    private final String mNetworkLocationProviderPackageName;
    private final String mGeocodeProviderPackageName;
    private PackageManager mPackageManager;  // final after initialize()
    private String mNetworkLocationProviderPackageName;  // only used on handler thread
    private String mGeocodeProviderPackageName;  // only used on handler thread
    private GeocoderProxy mGeocodeProvider;
    private IGpsStatusProvider mGpsStatusProvider;
    private INetInitiatedListener mNetInitiatedListener;
@@ -490,25 +495,78 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        addProvider(passiveProvider);
        mEnabledProviders.add(passiveProvider.getName());

        // initialize external network location and geocoder services
        PackageManager pm = mContext.getPackageManager();
        if (mNetworkLocationProviderPackageName != null &&
                pm.resolveService(new Intent(mNetworkLocationProviderPackageName), 0) != null) {
            mNetworkLocationProvider =
                new LocationProviderProxy(mContext, LocationManager.NETWORK_PROVIDER,
                        mNetworkLocationProviderPackageName, mLocationHandler);

        // initialize external network location and geocoder services.
        // The initial value of mNetworkLocationProviderPackageName and
        // mGeocodeProviderPackageName is just used to determine what
        // signatures future mNetworkLocationProviderPackageName and
        // mGeocodeProviderPackageName packages must have. So alternate
        // providers can be installed under a different package name
        // so long as they have the same signature as the original
        // provider packages.
        if (mNetworkLocationProviderPackageName != null) {
            String packageName = findBestPackage(LocationProviderProxy.SERVICE_ACTION,
                    mNetworkLocationProviderPackageName);
            if (packageName != null) {
                mNetworkLocationProvider = new LocationProviderProxy(mContext,
                        LocationManager.NETWORK_PROVIDER,
                        packageName, mLocationHandler);
                mNetworkLocationProviderPackageName = packageName;
                addProvider(mNetworkLocationProvider);
            }

        if (mGeocodeProviderPackageName != null &&
                pm.resolveService(new Intent(mGeocodeProviderPackageName), 0) != null) {
            mGeocodeProvider = new GeocoderProxy(mContext, mGeocodeProviderPackageName);
        }
        if (mGeocodeProviderPackageName != null) {
            String packageName = findBestPackage(GeocoderProxy.SERVICE_ACTION,
                    mGeocodeProviderPackageName);
            if (packageName != null) {
                mGeocodeProvider = new GeocoderProxy(mContext, packageName);
                mGeocodeProviderPackageName = packageName;
            }
        }

        updateProvidersLocked();
    }

    /**
     * Pick the best (network location provider or geocode provider) package.
     * The best package:
     * - implements serviceIntentName
     * - has signatures that match that of sigPackageName
     * - has the highest version value in a meta-data field in the service component
     */
    String findBestPackage(String serviceIntentName, String sigPackageName) {
        Intent intent = new Intent(serviceIntentName);
        List<ResolveInfo> infos = mPackageManager.queryIntentServices(intent,
                PackageManager.GET_META_DATA);
        if (infos == null) return null;

        int bestVersion = Integer.MIN_VALUE;
        String bestPackage = null;
        for (ResolveInfo info : infos) {
            String packageName = info.serviceInfo.packageName;
            // check signature
            if (mPackageManager.checkSignatures(packageName, sigPackageName) !=
                    PackageManager.SIGNATURE_MATCH) {
                Slog.w(TAG, packageName + " implements " + serviceIntentName +
                       " but its signatures don't match those in " + sigPackageName +
                       ", ignoring");
                continue;
            }
            // read version
            int version = 0;
            if (info.serviceInfo.metaData != null) {
                version = info.serviceInfo.metaData.getInt("version", 0);
            }
            if (LOCAL_LOGV) Slog.v(TAG, packageName + " implements " + serviceIntentName +
                    " with version " + version);
            if (version > bestVersion) {
                bestVersion = version;
                bestPackage = packageName;
            }
        }

        return bestPackage;
    }

    /**
     * @param context the context that the LocationManagerService runs in
     */
@@ -516,10 +574,12 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        super();
        mContext = context;
        Resources resources = context.getResources();

        mNetworkLocationProviderPackageName = resources.getString(
                com.android.internal.R.string.config_networkLocationProvider);
                com.android.internal.R.string.config_networkLocationProviderPackageName);
        mGeocodeProviderPackageName = resources.getString(
                com.android.internal.R.string.config_geocodeProvider);
                com.android.internal.R.string.config_geocodeProviderPackageName);

        mPackageMonitor.register(context, null, true);

        if (LOCAL_LOGV) {
@@ -537,6 +597,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        // 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);
        mPackageManager = mContext.getPackageManager();

        // Load providers
        loadProviders();
@@ -1886,16 +1947,33 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
                    }
                } 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();
                    // reconnect to external providers if there is a better package
                    if (mNetworkLocationProviderPackageName != null &&
                            mPackageManager.resolveService(
                            new Intent(LocationProviderProxy.SERVICE_ACTION)
                            .setPackage(packageName), 0) != null) {
                        // package implements service, perform full check
                        String bestPackage = findBestPackage(
                                LocationProviderProxy.SERVICE_ACTION,
                                mNetworkLocationProviderPackageName);
                        if (packageName.equals(bestPackage)) {
                            mNetworkLocationProvider.reconnect(bestPackage);
                            mNetworkLocationProviderPackageName = packageName;
                        }
                    }
                    if (mGeocodeProviderPackageName != null &&
                            mPackageManager.resolveService(
                            new Intent(GeocoderProxy.SERVICE_ACTION)
                            .setPackage(packageName), 0) != null) {
                        // package implements service, perform full check
                        String bestPackage = findBestPackage(
                                GeocoderProxy.SERVICE_ACTION,
                                mGeocodeProviderPackageName);
                        if (packageName.equals(bestPackage)) {
                            mGeocodeProvider.reconnect(bestPackage);
                            mGeocodeProviderPackageName = packageName;
                        }
                    if (mGeocodeProvider != null &&
                        mGeocodeProviderPackageName.startsWith(packageDot)) {
                        mGeocodeProvider.reconnect();
                    }
                }
            } catch (Exception e) {
@@ -2004,6 +2082,11 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
            // Called by main thread; divert work to LocationWorker.
            Message.obtain(mLocationHandler, MESSAGE_PACKAGE_UPDATED, packageName).sendToTarget();
        }
        @Override
        public void onPackageAdded(String packageName, int uid) {
            // Called by main thread; divert work to LocationWorker.
            Message.obtain(mLocationHandler, MESSAGE_PACKAGE_UPDATED, packageName).sendToTarget();
        }
    };

    // Wake locks
+13 −12
Original line number Diff line number Diff line
@@ -39,27 +39,28 @@ public class GeocoderProxy {

    private static final String TAG = "GeocoderProxy";

    public static final String SERVICE_ACTION =
        "com.android.location.service.GeocodeProvider";

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

    public GeocoderProxy(Context context, String serviceName) {
    public GeocoderProxy(Context context, String packageName) {
        mContext = context;
        mIntent = new Intent(serviceName);
        mContext.bindService(mIntent, mServiceConnection,
                Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
                | Context.BIND_ALLOW_OOM_MANAGEMENT);
        mIntent = new Intent(SERVICE_ACTION);
        reconnect(packageName);
    }

    /**
     * When unbundled NetworkLocationService package is updated, we
     * need to unbind from the old version and re-bind to the new one.
     */
    public void reconnect() {
    /** Bind to service. Will reconnect if already connected */
    public void reconnect(String packageName) {
        synchronized (mMutex) {
            if (mServiceConnection != null) {
                mContext.unbindService(mServiceConnection);
            }
            mServiceConnection = new Connection();
            mIntent.setPackage(packageName);
            mContext.bindService(mIntent, mServiceConnection,
                    Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
                    | Context.BIND_ALLOW_OOM_MANAGEMENT);
+15 −14
Original line number Diff line number Diff line
@@ -42,12 +42,15 @@ public class LocationProviderProxy implements LocationProviderInterface {

    private static final String TAG = "LocationProviderProxy";

    public static final String SERVICE_ACTION =
        "com.android.location.service.NetworkLocationProvider";

    private final Context mContext;
    private final String mName;
    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
    private Connection mServiceConnection;  // never null after ctor

    // cached values set by the location manager
    private boolean mLocationTracking = false;
@@ -58,28 +61,26 @@ public class LocationProviderProxy implements LocationProviderInterface {
    private NetworkInfo mNetworkInfo;

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

    /**
     * When unbundled NetworkLocationService package is updated, we
     * need to unbind from the old version and re-bind to the new one.
     */
    public void reconnect() {
    /** Bind to service. Will reconnect if already connected */
    public void reconnect(String packageName) {
        synchronized (mMutex) {
            if (mServiceConnection != null) {
                mContext.unbindService(mServiceConnection);
            }
            mServiceConnection = new Connection();
            mIntent.setPackage(packageName);
            mContext.bindService(mIntent, mServiceConnection,
                    Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
                    | Context.BIND_ALLOW_OOM_MANAGEMENT);
                    Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND |
                    Context.BIND_ALLOW_OOM_MANAGEMENT);
        }
    }