Home | History | Annotate | Download | only in api22
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.net.cts.legacy.api22;
     18 
     19 import android.content.BroadcastReceiver;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.IntentFilter;
     23 import android.content.pm.PackageManager;
     24 import android.net.ConnectivityManager;
     25 import android.net.LinkAddress;
     26 import android.net.LinkProperties;
     27 import android.net.Network;
     28 import android.net.NetworkInfo;
     29 import android.net.wifi.WifiManager;
     30 import android.os.ConditionVariable;
     31 import android.test.AndroidTestCase;
     32 import android.util.Log;
     33 
     34 import java.net.DatagramSocket;
     35 import java.net.Inet4Address;
     36 import java.net.InetAddress;
     37 import java.util.ArrayList;
     38 import java.util.List;
     39 
     40 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
     41 import static android.net.ConnectivityManager.TYPE_MOBILE;
     42 import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
     43 import static android.net.ConnectivityManager.TYPE_VPN;
     44 import static android.net.ConnectivityManager.TYPE_WIFI;
     45 
     46 public class ConnectivityManagerLegacyTest extends AndroidTestCase {
     47     private static final String TAG = ConnectivityManagerLegacyTest.class.getSimpleName();
     48     private static final String FEATURE_ENABLE_HIPRI = "enableHIPRI";
     49     private static final String HOST_ADDRESS1 = "192.0.2.1";
     50     private static final String HOST_ADDRESS2 = "192.0.2.2";
     51     private static final String HOST_ADDRESS3 = "192.0.2.3";
     52 
     53     // These are correct as of API level 22, which is what we target here.
     54     private static final int APN_REQUEST_FAILED = 3;
     55     private static final int MAX_NETWORK_TYPE = TYPE_VPN;
     56 
     57     private ConnectivityManager mCm;
     58     private WifiManager mWifiManager;
     59     private PackageManager mPackageManager;
     60 
     61     private final List<Integer>mProtectedNetworks = new ArrayList<Integer>();
     62 
     63     protected void setUp() throws Exception {
     64         super.setUp();
     65         mCm = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
     66         mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
     67         mPackageManager = getContext().getPackageManager();
     68 
     69         // Get com.android.internal.R.array.config_protectedNetworks
     70         int resId = getContext().getResources().getIdentifier("config_protectedNetworks", "array", "android");
     71         int[] protectedNetworks = getContext().getResources().getIntArray(resId);
     72         for (int p : protectedNetworks) {
     73             mProtectedNetworks.add(p);
     74         }
     75     }
     76 
     77     // true if only the system can turn it on
     78     private boolean isNetworkProtected(int networkType) {
     79         return mProtectedNetworks.contains(networkType);
     80     }
     81 
     82     private int ipv4AddrToInt(String addrString) throws Exception {
     83         byte[] addr = ((Inet4Address) InetAddress.getByName(addrString)).getAddress();
     84         return ((addr[3] & 0xff) << 24) | ((addr[2] & 0xff) << 16) |
     85                 ((addr[1] & 0xff) << 8) | (addr[0] & 0xff);
     86     }
     87 
     88     // Returns a list of all the IP addresses for all the networks of a given legacy type. We can't
     89     // just fetch the IP addresses for that type because there is no public getLinkProperties API
     90     // that takes a legacy type.
     91     private List<InetAddress> getIpAddresses(int type) {
     92         ArrayList<InetAddress> addresses = new ArrayList<>();
     93         Network[] networks = mCm.getAllNetworks();
     94         for (int i = 0; i < networks.length; i++) {
     95             NetworkInfo ni = mCm.getNetworkInfo(networks[i]);
     96             if (ni != null && ni.getType() == type) {
     97                 // This does not include IP addresses on stacked interfaces (e.g., 464xlat), because
     98                 // there is no public API that will return them.
     99                 LinkProperties lp = mCm.getLinkProperties(networks[i]);
    100                 for (LinkAddress address : lp.getLinkAddresses()) {
    101                     addresses.add(address.getAddress());
    102                 }
    103             }
    104         }
    105         return addresses;
    106     }
    107 
    108     private boolean hasIPv4(int type) {
    109         for (InetAddress address : getIpAddresses(type)) {
    110             if (address instanceof Inet4Address) {
    111                 return true;
    112             }
    113         }
    114         return false;
    115     }
    116 
    117     private void checkSourceAddress(String addrString, int type) throws Exception {
    118         // The public requestRouteToHost API only supports IPv4, but it will not return failure if
    119         // the network does not have an IPv4 address. So don't check that it's working unless we
    120         // know that the network has an IPv4 address. Note that it's possible that the network will
    121         // have an IPv4 address but we don't know about it, because the IPv4 address might be on a
    122         // stacked interface and we wouldn't be able to see it.
    123         if (!hasIPv4(type)) {
    124             Log.d(TAG, "Not checking source address on network type " + type + ", no IPv4 address");
    125             return;
    126         }
    127 
    128         DatagramSocket d = new DatagramSocket();
    129         d.connect(InetAddress.getByName(addrString), 7);
    130         InetAddress localAddress = d.getLocalAddress();
    131         String localAddrString = localAddress.getHostAddress();
    132 
    133         Log.d(TAG, "Got source address " + localAddrString + " for destination " + addrString);
    134 
    135         assertTrue(
    136                 "Local address " + localAddress + " not assigned to any network of type " + type,
    137                 getIpAddresses(type).contains(localAddress));
    138 
    139         Log.d(TAG, "Source address " + localAddress + " found on network type " + type);
    140     }
    141 
    142     /** Test that hipri can be brought up when Wifi is enabled. */
    143     public void testStartUsingNetworkFeature_enableHipri() throws Exception {
    144         if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
    145                 || !mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
    146             // This test requires a mobile data connection and WiFi.
    147             return;
    148         }
    149 
    150         // Make sure WiFi is connected to an access point.
    151         boolean isWifiEnabled = isWifiConnected();
    152         try {
    153             if (!isWifiEnabled) {
    154                 connectToWifi();
    155             }
    156 
    157             expectNetworkBroadcast(TYPE_MOBILE_HIPRI, NetworkInfo.State.CONNECTED, new Runnable() {
    158                 public void run() {
    159                     int ret = mCm.startUsingNetworkFeature(TYPE_MOBILE, FEATURE_ENABLE_HIPRI);
    160                     assertTrue("Couldn't start using the HIPRI feature.", ret != -1);
    161                 }
    162             });
    163 
    164             assertTrue("Couldn't requestRouteToHost using HIPRI.",
    165                     mCm.requestRouteToHost(TYPE_MOBILE_HIPRI, ipv4AddrToInt(HOST_ADDRESS1)));
    166 
    167             checkSourceAddress(HOST_ADDRESS1, TYPE_MOBILE);
    168             checkSourceAddress(HOST_ADDRESS2, TYPE_WIFI);
    169 
    170             // TODO check dns selection
    171 
    172             expectNetworkBroadcast(TYPE_MOBILE_HIPRI, NetworkInfo.State.DISCONNECTED, new Runnable() {
    173                 public void run() {
    174                     int ret = mCm.stopUsingNetworkFeature(TYPE_MOBILE, FEATURE_ENABLE_HIPRI);
    175                     assertTrue("Couldn't stop using the HIPRI feature.", ret != -1);
    176                 }
    177             });
    178 
    179             // TODO check dns selection
    180         } finally {
    181             if (!isWifiEnabled && isWifiConnected()) {
    182                 disconnectFromWifi();
    183             }
    184         }
    185     }
    186 
    187     public void testStartUsingNetworkFeature() {
    188 
    189         final String invalidFeature = "invalidFeature";
    190         final String mmsFeature = "enableMMS";
    191         final int failureCode = -1;
    192         final int wifiOnlyStartFailureCode = APN_REQUEST_FAILED;
    193         final int wifiOnlyStopFailureCode = -1;
    194 
    195         NetworkInfo ni = mCm.getNetworkInfo(TYPE_MOBILE);
    196         if (ni != null) {
    197             assertEquals(APN_REQUEST_FAILED,
    198                     mCm.startUsingNetworkFeature(TYPE_MOBILE, invalidFeature));
    199             assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE, invalidFeature));
    200         } else {
    201             assertEquals(wifiOnlyStartFailureCode, mCm.startUsingNetworkFeature(TYPE_MOBILE,
    202                     invalidFeature));
    203             assertEquals(wifiOnlyStopFailureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE,
    204                     invalidFeature));
    205         }
    206 
    207         ni = mCm.getNetworkInfo(TYPE_WIFI);
    208         if (ni != null) {
    209             // Should return failure because MMS is not supported on WIFI.
    210             assertEquals(APN_REQUEST_FAILED, mCm.startUsingNetworkFeature(TYPE_WIFI,
    211                     mmsFeature));
    212             assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_WIFI,
    213                     mmsFeature));
    214         }
    215     }
    216 
    217     private void expectNetworkBroadcast(final int type, final NetworkInfo.State state,
    218             Runnable afterWhat) {
    219         final int TIMEOUT_MS = 30 * 1000;
    220         final ConditionVariable var = new ConditionVariable();
    221 
    222         Log.d(TAG, "Waiting for " + state + " broadcast for type " + type);
    223         BroadcastReceiver receiver = new BroadcastReceiver() {
    224             public void onReceive(Context context, Intent intent) {
    225                 NetworkInfo ni = intent.getExtras()
    226                         .getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO);
    227                 assertNotNull("CONNECTIVITY_ACTION with null EXTRA_NETWORK_INFO", ni);
    228                 if (ni.getType() == type && ni.getState().equals(state)) {
    229                     Log.d(TAG, "Received expected " + state + " broadcast for type " + type);
    230                     var.open();
    231                 }
    232             }
    233         };
    234         IntentFilter filter = new IntentFilter();
    235         filter.addAction(CONNECTIVITY_ACTION);
    236         mContext.registerReceiver(receiver, filter);
    237 
    238         try {
    239             afterWhat.run();
    240             final String msg = "Did not receive expected " + state + " broadcast for type " + type +
    241                     " after " + TIMEOUT_MS + " ms";
    242             assertTrue(msg, var.block(TIMEOUT_MS));
    243         } finally {
    244             mContext.unregisterReceiver(receiver);
    245         }
    246     }
    247 
    248     private boolean isWifiConnected() {
    249         NetworkInfo ni = mCm.getNetworkInfo(TYPE_WIFI);
    250         return ni != null && ni.isConnected();
    251     }
    252 
    253     private void setWifiState(final boolean enabled) {
    254         if (enabled != isWifiConnected()) {
    255             final NetworkInfo.State desiredState = enabled ?
    256                     NetworkInfo.State.CONNECTED :
    257                     NetworkInfo.State.DISCONNECTED;
    258             expectNetworkBroadcast(TYPE_WIFI, desiredState, new Runnable() {
    259                 public void run() {
    260                     mWifiManager.setWifiEnabled(enabled);
    261                 }
    262             });
    263         }
    264     }
    265 
    266     private void connectToWifi() {
    267         setWifiState(true);
    268     }
    269 
    270     private void disconnectFromWifi() {
    271         setWifiState(false);
    272     }
    273 
    274     private boolean isNetworkSupported(int networkType) {
    275         return mCm.getNetworkInfo(networkType) != null;
    276     }
    277 
    278     public void testRequestRouteToHost() throws Exception {
    279         for (int type = -1 ; type <= MAX_NETWORK_TYPE; type++) {
    280             NetworkInfo ni = mCm.getNetworkInfo(type);
    281             boolean expectToWork = isNetworkSupported(type) && !isNetworkProtected(type) &&
    282                     ni != null && ni.isConnected();
    283 
    284             try {
    285                 assertTrue("Network type " + type,
    286                         mCm.requestRouteToHost(type, ipv4AddrToInt(HOST_ADDRESS3)) == expectToWork);
    287             } catch (Exception e) {
    288                 Log.d(TAG, "got exception in requestRouteToHost for type " + type);
    289                 assertFalse("Exception received for type " + type, expectToWork);
    290             }
    291 
    292             //TODO verify route table
    293         }
    294 
    295         assertFalse(mCm.requestRouteToHost(-1, ipv4AddrToInt(HOST_ADDRESS1)));
    296     }
    297 }
    298