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

Commit 59502ebc authored by Jeremy Joslin's avatar Jeremy Joslin
Browse files

NetworkRecommendationProviders require the location permission.

Any NetworkRecommendationProvider bound to by the system must have
access to location (i.e. it holds the location permission and
location is enabled on the device).

If the location permission is revoked then the binding will be
disconnected and the system will revert to the default network
recommendation provider (if set and valid). If location access
is disabled on the device then the binding will be disconnected
but the system won't fall back to the default provider (because
it won't have location either), instead the current provider will
be re-enabled when location access is enabled again.

BUG:62263953
Test: runtest frameworks-services -c com.android.server.NetworkScoreServiceTest
Test: runtest frameworks-services -c com.android.server.NetworkScorerAppManagerTest
Change-Id: I93c37eeda47840d92f3ca52767e878dc19b46740
(cherry picked from commit d816abe9)
parent 6e8e322e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import java.util.concurrent.Executor;
 * A network recommendation provider is any application which:
 * <ul>
 * <li>Is granted the {@link permission#SCORE_NETWORKS} permission.
 * <li>Is granted the {@link permission#ACCESS_COARSE_LOCATION} permission.
 * <li>Includes a Service for the {@link NetworkScoreManager#ACTION_RECOMMEND_NETWORKS} intent
 *     which is protected by the {@link permission#BIND_NETWORK_RECOMMENDATION_SERVICE} permission.
 * </ul>
+2 −1
Original line number Diff line number Diff line
@@ -38,7 +38,8 @@ import java.util.List;
 *
 * <p>A network scorer is any application which:
 * <ul>
 * <li>Declares the {@link permission#SCORE_NETWORKS} permission.
 * <li>Is granted the {@link permission#SCORE_NETWORKS} permission.
 * <li>Is granted the {@link permission#ACCESS_COARSE_LOCATION} permission.
 * <li>Include a Service for the {@link #ACTION_RECOMMEND_NETWORKS} action
 *     protected by the {@link permission#BIND_NETWORK_RECOMMENDATION_SERVICE}
 *     permission.
+1 −0
Original line number Diff line number Diff line
@@ -1388,6 +1388,7 @@
    <!-- The package name of the default network recommendation app.
         A network recommendation provider must:
             * Be granted the SCORE_NETWORKS permission.
             * Be granted the ACCESS_COARSE_LOCATION permission.
             * Include a Service for the android.net.scoring.RECOMMEND_NETWORKS action
               protected by the BIND_NETWORK_RECOMMENDATION_SERVICE permission.

+15 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.location.LocationManager;
import android.net.INetworkRecommendationProvider;
import android.net.INetworkScoreCache;
import android.net.INetworkScoreService;
@@ -113,6 +114,16 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
        }
    };

    private BroadcastReceiver mLocationModeReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            if (LocationManager.MODE_CHANGED_ACTION.equals(action)) {
                refreshBinding();
            }
        }
    };

    /**
     * Clears scores when the active scorer package is no longer valid and
     * manages the service connection.
@@ -241,6 +252,10 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
                mUserIntentReceiver, UserHandle.SYSTEM, filter, null /* broadcastPermission*/,
                null /* scheduler */);
        mHandler = new ServiceHandler(looper);
        IntentFilter locationModeFilter = new IntentFilter(LocationManager.MODE_CHANGED_ACTION);
        mContext.registerReceiverAsUser(
                mLocationModeReceiver, UserHandle.SYSTEM, locationModeFilter,
                null /* broadcastPermission*/, mHandler);
        mContentObserver = new DispatchingContentObserver(context, mHandler);
        mServiceConnProducer = serviceConnProducer;
    }
+44 −15
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server;

import android.Manifest.permission;
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -79,7 +80,7 @@ public class NetworkScorerAppManager {
        List<NetworkScorerAppData> appDataList = new ArrayList<>();
        for (int i = 0; i < resolveInfos.size(); i++) {
            final ServiceInfo serviceInfo = resolveInfos.get(i).serviceInfo;
            if (hasPermissions(serviceInfo.packageName)) {
            if (hasPermissions(serviceInfo.applicationInfo.uid, serviceInfo.packageName)) {
                if (VERBOSE) {
                    Log.v(TAG, serviceInfo.packageName + " is a valid scorer/recommender.");
                }
@@ -197,12 +198,33 @@ public class NetworkScorerAppManager {
        return null;
    }

    private boolean hasPermissions(String packageName) {
    private boolean hasPermissions(final int uid, final String packageName) {
        return hasScoreNetworksPermission(packageName)
                && canAccessLocation(uid, packageName);
    }

    private boolean hasScoreNetworksPermission(String packageName) {
        final PackageManager pm = mContext.getPackageManager();
        return pm.checkPermission(permission.SCORE_NETWORKS, packageName)
                == PackageManager.PERMISSION_GRANTED;
    }

    private boolean canAccessLocation(int uid, String packageName) {
        final PackageManager pm = mContext.getPackageManager();
        final AppOpsManager appOpsManager =
                (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
        return isLocationModeEnabled()
                && pm.checkPermission(permission.ACCESS_COARSE_LOCATION, packageName)
                == PackageManager.PERMISSION_GRANTED
                && appOpsManager.noteOp(AppOpsManager.OP_COARSE_LOCATION, uid, packageName)
                == AppOpsManager.MODE_ALLOWED;
    }

    private boolean isLocationModeEnabled() {
        return mSettingsFacade.getSecureInt(mContext, Settings.Secure.LOCATION_MODE,
                Settings.Secure.LOCATION_MODE_OFF) != Settings.Secure.LOCATION_MODE_OFF;
    }

    /**
     * Set the specified package as the default scorer application.
     *
@@ -270,23 +292,20 @@ public class NetworkScorerAppManager {
            return;
        }

        // the active scorer isn't valid, revert to the default if it's different
        int newEnabledSetting = NetworkScoreManager.RECOMMENDATIONS_ENABLED_OFF;
        // the active scorer isn't valid, revert to the default if it's different and valid
        final String defaultPackageName = getDefaultPackageSetting();
        if (!TextUtils.equals(currentPackageName, defaultPackageName)) {
            setNetworkRecommendationsPackage(defaultPackageName);
        if (!TextUtils.equals(currentPackageName, defaultPackageName)
                && getScorer(defaultPackageName) != null) {
            if (DEBUG) {
                Log.d(TAG, "Defaulted the network recommendations app to: " + defaultPackageName);
            }
            if (getScorer(defaultPackageName) != null) { // the default is valid
                if (DEBUG) Log.d(TAG, defaultPackageName + " is now the active scorer.");
                setNetworkRecommendationsEnabledSetting(
                        NetworkScoreManager.RECOMMENDATIONS_ENABLED_ON);
            } else { // the default isn't valid either, we're disabled at this point
                if (DEBUG) Log.d(TAG, defaultPackageName + " is not an active scorer.");
                setNetworkRecommendationsEnabledSetting(
                        NetworkScoreManager.RECOMMENDATIONS_ENABLED_OFF);
                Log.d(TAG, "Defaulting the network recommendations app to: "
                        + defaultPackageName);
            }
            setNetworkRecommendationsPackage(defaultPackageName);
            newEnabledSetting = NetworkScoreManager.RECOMMENDATIONS_ENABLED_ON;
        }

        setNetworkRecommendationsEnabledSetting(newEnabledSetting);
    }

    /**
@@ -352,6 +371,9 @@ public class NetworkScorerAppManager {
    private void setNetworkRecommendationsPackage(String packageName) {
        mSettingsFacade.putString(mContext,
                Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, packageName);
        if (VERBOSE) {
            Log.d(TAG, Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE + " set to " + packageName);
        }
    }

    private int getNetworkRecommendationsEnabledSetting() {
@@ -361,6 +383,9 @@ public class NetworkScorerAppManager {
    private void setNetworkRecommendationsEnabledSetting(int value) {
        mSettingsFacade.putInt(mContext,
                Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, value);
        if (VERBOSE) {
            Log.d(TAG, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED + " set to " + value);
        }
    }

    /**
@@ -382,5 +407,9 @@ public class NetworkScorerAppManager {
        public int getInt(Context context, String name, int defaultValue) {
            return Settings.Global.getInt(context.getContentResolver(), name, defaultValue);
        }

        public int getSecureInt(Context context, String name, int defaultValue) {
            return Settings.Secure.getInt(context.getContentResolver(), name, defaultValue);
        }
    }
}
Loading