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

Commit ffc42b0b authored by Lorenzo Colitti's avatar Lorenzo Colitti
Browse files

Stop supporting legacy ConnectivityManager routing methods in M.

The methods startUsingNetworkFeature, stopUsingNetworkFeature and
requestRouteToHost were @removed in all the M preview builds, but
internal and external developers have noted that this imposes
additional burden for applications that need to work across
multiple platform versions because it causes compile-time errors.

We switched from @removed back to @deprecated to avoid these
problems. In order to effectively deprecate these methods, which
are error-prone and insecure, make them throw
UnsupportedOperationException if the app's target SDK is M or
above.

Because there are still one or two places in system code that use
these APIs, exempt Process.SYSTEM_UID and the OMA-DM client from
the check for now.

Bug: 22728205
Change-Id: I790bd32f3aa8067cbb625962a209bb9232f4b58c
parent 5db4cc8f
Loading
Loading
Loading
Loading
+30 −3
Original line number Diff line number Diff line
@@ -220,11 +220,12 @@ final class SystemServiceRegistry {
        SYSTEM_SERVICE_NAMES.put(android.text.ClipboardManager.class, Context.CLIPBOARD_SERVICE);

        registerService(Context.CONNECTIVITY_SERVICE, ConnectivityManager.class,
                new StaticServiceFetcher<ConnectivityManager>() {
                new StaticOuterContextServiceFetcher<ConnectivityManager>() {
            @Override
            public ConnectivityManager createService() {
            public ConnectivityManager createService(Context context) {
                IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
                return new ConnectivityManager(IConnectivityManager.Stub.asInterface(b));
                IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
                return new ConnectivityManager(context, service);
            }});

        registerService(Context.COUNTRY_DETECTOR, CountryDetector.class,
@@ -793,4 +794,30 @@ final class SystemServiceRegistry {

        public abstract T createService();
    }

    /**
     * Like StaticServiceFetcher, creates only one instance of the service per process, but when
     * creating the service for the first time, passes it the outer context of the creating
     * component.
     *
     * TODO: Is this safe in the case where multiple applications share the same process?
     * TODO: Delete this once its only user (ConnectivityManager) is known to work well in the
     * case where multiple application components each have their own ConnectivityManager object.
     */
    static abstract class StaticOuterContextServiceFetcher<T> implements ServiceFetcher<T> {
        private T mCachedInstance;

        @Override
        public final T getService(ContextImpl ctx) {
            synchronized (StaticOuterContextServiceFetcher.this) {
                if (mCachedInstance == null) {
                    mCachedInstance = createService(ctx.getOuterContext());
                }
                return mCachedInstance;
            }
        }

        public abstract T createService(Context applicationContext);
    }

}
+43 −1
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.annotation.SdkConstant.SdkConstantType;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.NetworkUtils;
import android.os.Binder;
import android.os.Build.VERSION_CODES;
@@ -33,6 +34,7 @@ import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
@@ -490,6 +492,8 @@ public class ConnectivityManager {
     */
    private static ConnectivityManager sInstance;

    private final Context mContext;

    private INetworkManagementService mNMService;

    /**
@@ -892,8 +896,11 @@ public class ConnectivityManager {
     *
     * @deprecated Deprecated in favor of the cleaner
     *             {@link #requestNetwork(NetworkRequest, NetworkCallback)} API.
     *             In {@link VERSION_CODES#MNC}, and above, this method is unsupported and will
     *             throw {@code UnsupportedOperationException} if called.
     */
    public int startUsingNetworkFeature(int networkType, String feature) {
        checkLegacyRoutingApiAccess();
        NetworkCapabilities netCap = networkCapabilitiesForFeature(networkType, feature);
        if (netCap == null) {
            Log.d(TAG, "Can't satisfy startUsingNetworkFeature for " + networkType + ", " +
@@ -939,8 +946,11 @@ public class ConnectivityManager {
     * always indicates failure.
     *
     * @deprecated Deprecated in favor of the cleaner {@link #unregisterNetworkCallback} API.
     *             In {@link VERSION_CODES#MNC}, and above, this method is unsupported and will
     *             throw {@code UnsupportedOperationException} if called.
     */
    public int stopUsingNetworkFeature(int networkType, String feature) {
        checkLegacyRoutingApiAccess();
        NetworkCapabilities netCap = networkCapabilitiesForFeature(networkType, feature);
        if (netCap == null) {
            Log.d(TAG, "Can't satisfy stopUsingNetworkFeature for " + networkType + ", " +
@@ -1218,6 +1228,8 @@ public class ConnectivityManager {
     * @deprecated Deprecated in favor of the
     *             {@link #requestNetwork(NetworkRequest, NetworkCallback)},
     *             {@link #bindProcessToNetwork} and {@link Network#getSocketFactory} API.
     *             In {@link VERSION_CODES#MNC}, and above, this method is unsupported and will
     *             throw {@code UnsupportedOperationException} if called.
     */
    public boolean requestRouteToHost(int networkType, int hostAddress) {
        return requestRouteToHostAddress(networkType, NetworkUtils.intToInetAddress(hostAddress));
@@ -1238,6 +1250,7 @@ public class ConnectivityManager {
     *             {@link #bindProcessToNetwork} API.
     */
    public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) {
        checkLegacyRoutingApiAccess();
        try {
            return mService.requestRouteToHostAddress(networkType, hostAddress.getAddress());
        } catch (RemoteException e) {
@@ -1416,7 +1429,8 @@ public class ConnectivityManager {
    /**
     * {@hide}
     */
    public ConnectivityManager(IConnectivityManager service) {
    public ConnectivityManager(Context context, IConnectivityManager service) {
        mContext = checkNotNull(context, "missing context");
        mService = checkNotNull(service, "missing IConnectivityManager");
        sInstance = this;
    }
@@ -2703,6 +2717,34 @@ public class ConnectivityManager {
        return new Network(netId);
    }

    private void unsupportedStartingFrom(int version) {
        if (Process.myUid() == Process.SYSTEM_UID) {
            // The getApplicationInfo() call we make below is not supported in system context, and
            // we want to allow the system to use these APIs anyway.
            return;
        }

        if (mContext.getApplicationInfo().targetSdkVersion >= version) {
            throw new UnsupportedOperationException(
                    "This method is not supported in target SDK version " + version + " and above");
        }
    }

    // Checks whether the calling app can use the legacy routing API (startUsingNetworkFeature,
    // stopUsingNetworkFeature, requestRouteToHost), and if not throw UnsupportedOperationException.
    // TODO: convert the existing system users (Tethering, GpsLocationProvider) to the new APIs and
    // remove these exemptions. Note that this check is not secure, and apps can still access these
    // functions by accessing ConnectivityService directly. However, it should be clear that doing
    // so is unsupported and may break in the future. http://b/22728205
    private void checkLegacyRoutingApiAccess() {
        if (mContext.checkCallingOrSelfPermission("com.android.permission.INJECT_OMADM_SETTINGS")
                == PackageManager.PERMISSION_GRANTED) {
            return;
        }

        unsupportedStartingFrom(VERSION_CODES.MNC);
    }

    /**
     * Binds host resolutions performed by this process to {@code network}.
     * {@link #bindProcessToNetwork} takes precedence over this setting.
+1 −1
Original line number Diff line number Diff line
@@ -463,7 +463,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
        mService = new WrappedConnectivityService(
                mServiceContext, mNetManager, mStatsService, mPolicyService);
        mService.systemReady();
        mCm = new ConnectivityManager(mService);
        mCm = new ConnectivityManager(getContext(), mService);
    }

    private int transportToLegacyType(int transport) {