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

Commit e09aed49 authored by Jeff Hamilton's avatar Jeff Hamilton Committed by Android (Google) Code Review
Browse files

Merge "Changes to support updating location providers." into jb-mr1-dev

parents e9b533bf fbadb699
Loading
Loading
Loading
Loading
+1 −8
Original line number Diff line number Diff line
@@ -636,19 +636,12 @@
         of new location providers at run-time. The new package does not
         have to be explicitly listed here, however it must have a signature
         that matches the signature of at least one package on this list.
         Platforms should overlay additional packages in
         config_overlay_locationProviderPackageNames, instead of overlaying
         this config, if they only want to append packages and not replace
         the entire array.
         -->
    <string-array name="config_locationProviderPackageNames" translatable="false">
        <!-- The standard AOSP fused location provider -->
        <item>com.android.location.fused</item>
    </string-array>

    <!-- Pacakge name(s) supplied by overlay, and appended to
         config_locationProviderPackageNames. -->
    <string-array name="config_overlay_locationProviderPackageNames" translatable="false" />

    <!-- Boolean indicating if current platform supports bluetooth SCO for off call
    use cases -->
    <bool name="config_bluetooth_sco_off_call">true</bool>
+0 −1
Original line number Diff line number Diff line
@@ -1475,7 +1475,6 @@
  <java-symbol type="array" name="radioAttributes" />
  <java-symbol type="array" name="config_oemUsbModeOverride" />
  <java-symbol type="array" name="config_locationProviderPackageNames" />
  <java-symbol type="array" name="config_overlay_locationProviderPackageNames" />
  <java-symbol type="bool" name="config_animateScreenLights" />
  <java-symbol type="bool" name="config_automatic_brightness_available" />
  <java-symbol type="bool" name="config_sf_limitedAlpha" />
+3 −2
Original line number Diff line number Diff line
@@ -18,7 +18,8 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.android.location.fused"
        coreApp="true">
        coreApp="true"
        android:sharedUserId="android.uid.system">

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
@@ -39,7 +40,7 @@
           <intent-filter>
               <action android:name="com.android.location.service.FusedLocationProvider" />
           </intent-filter>
           <meta-data android:name="version" android:value="1" />
           <meta-data android:name="serviceVersion" android:value="0" />
        </service>
    </application>
</manifest>
+77 −7
Original line number Diff line number Diff line
@@ -23,8 +23,11 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.location.Address;
@@ -249,6 +252,74 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        updateProvidersLocked();
    }

    private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
        PackageManager pm = mContext.getPackageManager();
        String systemPackageName = mContext.getPackageName();
        ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);

        List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
                new Intent(FUSED_LOCATION_SERVICE_ACTION),
                PackageManager.GET_META_DATA, mCurrentUserId);
        for (ResolveInfo rInfo : rInfos) {
            String packageName = rInfo.serviceInfo.packageName;

            // Check that the signature is in the list of supported sigs. If it's not in
            // this list the standard provider binding logic won't bind to it.
            try {
                PackageInfo pInfo;
                pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
                if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
                    Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
                            ", but has wrong signature, ignoring");
                    continue;
                }
            } catch (NameNotFoundException e) {
                Log.e(TAG, "missing package: " + packageName);
                continue;
            }

            // Get the version info
            if (rInfo.serviceInfo.metaData == null) {
                Log.w(TAG, "Found fused provider without metadata: " + packageName);
                continue;
            }

            int version = rInfo.serviceInfo.metaData.getInt(
                    ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
            if (version == 0) {
                // This should be the fallback fused location provider.

                // Make sure it's in the system partition.
                if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                    if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
                    continue;
                }

                // Check that the fallback is signed the same as the OS
                // as a proxy for coreApp="true"
                if (pm.checkSignatures(systemPackageName, packageName)
                        != PackageManager.SIGNATURE_MATCH) {
                    if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
                            + packageName);
                    continue;
                }

                // Found a valid fallback.
                if (D) Log.d(TAG, "Found fallback provider: " + packageName);
                return;
            } else {
                if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
            }
        }

        throw new IllegalStateException("Unable to find a fused location provider that is in the "
                + "system partition with version 0 and signed with the platform certificate. "
                + "Such a package is needed to provide a default fused location provider in the "
                + "event that no other fused location provider has been installed or is currently "
                + "available. For example, coreOnly boot mode when decrypting the data "
                + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
    }

    private void loadProvidersLocked() {
        // create a passive location provider, which is always enabled
        PassiveProvider passiveProvider = new PassiveProvider(this);
@@ -278,14 +349,13 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        */
        Resources resources = mContext.getResources();
        ArrayList<String> providerPackageNames = new ArrayList<String>();
        String[] pkgs1 = resources.getStringArray(
        String[] pkgs = resources.getStringArray(
                com.android.internal.R.array.config_locationProviderPackageNames);
        String[] pkgs2 = resources.getStringArray(
                com.android.internal.R.array.config_overlay_locationProviderPackageNames);
        if (D) Log.d(TAG, "built-in location providers: " + Arrays.toString(pkgs1));
        if (D) Log.d(TAG, "overlay location providers: " + Arrays.toString(pkgs2));
        if (pkgs1 != null) providerPackageNames.addAll(Arrays.asList(pkgs1));
        if (pkgs2 != null) providerPackageNames.addAll(Arrays.asList(pkgs2));
        if (D) Log.d(TAG, "certificates for location providers pulled from: " +
                Arrays.toString(pkgs));
        if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));

        ensureFallbackFusedProviderPresentLocked(providerPackageNames);

        // bind to network provider
        LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
+31 −20
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@ import java.util.List;
 */
public class ServiceWatcher implements ServiceConnection {
    private static final boolean D = false;
    private static final String EXTRA_VERSION = "version";
    public static final String EXTRA_SERVICE_VERSION = "serviceVersion";

    private final String mTag;
    private final Context mContext;
@@ -58,9 +58,27 @@ public class ServiceWatcher implements ServiceConnection {
    // all fields below synchronized on mLock
    private IBinder mBinder;   // connected service
    private String mPackageName;  // current best package
    private int mVersion;  // current best version
    private int mVersion = Integer.MIN_VALUE;  // current best version
    private int mCurrentUserId;

    public static ArrayList<HashSet<Signature>> getSignatureSets(Context context,
            List<String> initialPackageNames) {
        PackageManager pm = context.getPackageManager();
        ArrayList<HashSet<Signature>> sigSets = new ArrayList<HashSet<Signature>>();
        for (int i = 0, size = initialPackageNames.size(); i < size; i++) {
            String pkg = initialPackageNames.get(i);
            try {
                HashSet<Signature> set = new HashSet<Signature>();
                Signature[] sigs = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES).signatures;
                set.addAll(Arrays.asList(sigs));
                sigSets.add(set);
            } catch (NameNotFoundException e) {
                Log.w("ServiceWatcher", pkg + " not found");
            }
        }
        return sigSets;
    }

    public ServiceWatcher(Context context, String logTag, String action,
            List<String> initialPackageNames, Runnable newServiceWork, Handler handler, int userId) {
        mContext = context;
@@ -71,20 +89,7 @@ public class ServiceWatcher implements ServiceConnection {
        mHandler = handler;
        mCurrentUserId = userId;

        mSignatureSets = new ArrayList<HashSet<Signature>>();
        for (int i=0; i < initialPackageNames.size(); i++) {
            String pkg = initialPackageNames.get(i);
            HashSet<Signature> set = new HashSet<Signature>();
            try {
                Signature[] sigs =
                        mPm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES).signatures;
                set.addAll(Arrays.asList(sigs));
                mSignatureSets.add(set);
            } catch (NameNotFoundException e) {
                Log.w(logTag, pkg + " not found");
            }
        }

        mSignatureSets = getSignatureSets(context, initialPackageNames);
    }

    public boolean start() {
@@ -132,15 +137,16 @@ public class ServiceWatcher implements ServiceConnection {
            // check version
            int version = 0;
            if (rInfo.serviceInfo.metaData != null) {
                version = rInfo.serviceInfo.metaData.getInt(EXTRA_VERSION, 0);
                version = rInfo.serviceInfo.metaData.getInt(EXTRA_SERVICE_VERSION, 0);
            }

            if (version > mVersion) {
                bestVersion = version;
                bestPackage = packageName;
            }
        }

        if (D) Log.d(mTag, String.format("bindBestPackage %s found %d, %s",
        if (D) Log.d(mTag, String.format("bindBestPackage for %s : %s found %d, %s", mAction,
                (justCheckThisPackage == null ? "" : "(" + justCheckThisPackage + ") "),
                rInfos.size(),
                (bestPackage == null ? "no new best package" : "new best packge: " + bestPackage)));
@@ -174,7 +180,8 @@ public class ServiceWatcher implements ServiceConnection {
                | Context.BIND_ALLOW_OOM_MANAGEMENT | Context.BIND_NOT_VISIBLE, mCurrentUserId);
    }

    private boolean isSignatureMatch(Signature[] signatures) {
    public static boolean isSignatureMatch(Signature[] signatures,
            List<HashSet<Signature>> sigSets) {
        if (signatures == null) return false;

        // build hashset of input to test against
@@ -184,7 +191,7 @@ public class ServiceWatcher implements ServiceConnection {
        }

        // test input against each of the signature sets
        for (HashSet<Signature> referenceSet : mSignatureSets) {
        for (HashSet<Signature> referenceSet : sigSets) {
            if (referenceSet.equals(inputSet)) {
                return true;
            }
@@ -192,6 +199,10 @@ public class ServiceWatcher implements ServiceConnection {
        return false;
    }

    private boolean isSignatureMatch(Signature[] signatures) {
        return isSignatureMatch(signatures, mSignatureSets);
    }

    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
        /**
         * Called when package has been reinstalled