1 /* 2 * Copyright (C) 2019 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 com.android.cts.verifier.wifi.testcase; 18 19 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; 20 import static android.net.NetworkCapabilities.TRANSPORT_WIFI; 21 22 import android.annotation.IntDef; 23 import android.annotation.NonNull; 24 import android.content.BroadcastReceiver; 25 import android.content.Context; 26 import android.net.ConnectivityManager; 27 import android.net.MacAddress; 28 import android.net.Network; 29 import android.net.NetworkRequest; 30 import android.net.NetworkSpecifier; 31 import android.net.wifi.ScanResult; 32 import android.net.wifi.WifiNetworkSpecifier; 33 import android.os.PatternMatcher; 34 import android.util.Log; 35 import android.util.Pair; 36 37 import com.android.cts.verifier.R; 38 import com.android.cts.verifier.wifi.BaseTestCase; 39 import com.android.cts.verifier.wifi.CallbackUtils; 40 41 import java.lang.annotation.Retention; 42 import java.lang.annotation.RetentionPolicy; 43 44 /** 45 * Test case for all {@link NetworkRequest} requests with specifier built using 46 * {@link WifiNetworkSpecifier.Builder#build()}. 47 */ 48 public class NetworkRequestTestCase extends BaseTestCase { 49 private static final String TAG = "NetworkRequestTestCase"; 50 private static final boolean DBG = true; 51 52 private static final String UNAVAILABLE_SSID = "blahblahblah"; 53 private static final String UNAVAILABLE_BSSID = "02:00:00:00:00:00"; 54 private static final int NETWORK_REQUEST_TIMEOUT_MS = 30_000; 55 private static final int CALLBACK_TIMEOUT_MS = 40_000; 56 57 public static final int NETWORK_SPECIFIER_SPECIFIC_SSID_BSSID = 0; 58 public static final int NETWORK_SPECIFIER_PATTERN_SSID_BSSID = 1; 59 public static final int NETWORK_SPECIFIER_UNAVAILABLE_SSID_BSSID = 2; 60 61 @IntDef(prefix = { "NETWORK_SPECIFIER_" }, value = { 62 NETWORK_SPECIFIER_SPECIFIC_SSID_BSSID, 63 NETWORK_SPECIFIER_PATTERN_SSID_BSSID, 64 NETWORK_SPECIFIER_UNAVAILABLE_SSID_BSSID, 65 }) 66 @Retention(RetentionPolicy.SOURCE) 67 public @interface NetworkSpecifierType{} 68 69 private final Object mLock = new Object(); 70 private final @NetworkSpecifierType int mNetworkSpecifierType; 71 72 private ConnectivityManager mConnectivityManager; 73 private NetworkRequest mNetworkRequest; 74 private CallbackUtils.NetworkCallback mNetworkCallback; 75 private String mFailureReason; 76 77 public NetworkRequestTestCase(Context context, @NetworkSpecifierType int networkSpecifierType) { 78 super(context); 79 mNetworkSpecifierType = networkSpecifierType; 80 } 81 82 // Create a network specifier based on the test type. 83 private NetworkSpecifier createNetworkSpecifier(@NonNull ScanResult scanResult) 84 throws InterruptedException { 85 WifiNetworkSpecifier.Builder configBuilder = new WifiNetworkSpecifier.Builder(); 86 switch (mNetworkSpecifierType) { 87 case NETWORK_SPECIFIER_SPECIFIC_SSID_BSSID: 88 configBuilder.setSsid(scanResult.SSID); 89 configBuilder.setBssid(MacAddress.fromString(scanResult.BSSID)); 90 break; 91 case NETWORK_SPECIFIER_PATTERN_SSID_BSSID: 92 String ssidPrefix = scanResult.SSID.substring(0, scanResult.SSID.length() - 1); 93 MacAddress bssidMask = MacAddress.fromString("ff:ff:ff:ff:ff:00"); 94 configBuilder.setSsidPattern( 95 new PatternMatcher(ssidPrefix, PatternMatcher.PATTERN_PREFIX)); 96 configBuilder.setBssidPattern(MacAddress.fromString(scanResult.BSSID), bssidMask); 97 break; 98 case NETWORK_SPECIFIER_UNAVAILABLE_SSID_BSSID: 99 String ssid = UNAVAILABLE_SSID; 100 MacAddress bssid = MacAddress.fromString(UNAVAILABLE_BSSID); 101 if (mTestUtils.findNetworkInScanResultsResults(ssid, bssid.toString())) { 102 Log.e(TAG, "The specifiers chosen match a network in scan results." 103 + "Test will fail"); 104 return null; 105 } 106 configBuilder.setSsid(UNAVAILABLE_SSID); 107 configBuilder.setBssid(bssid); 108 break; 109 default: 110 throw new IllegalStateException("Unknown specifier type specifier"); 111 } 112 return configBuilder.build(); 113 } 114 115 116 private void setFailureReason(String reason) { 117 synchronized (mLock) { 118 mFailureReason = reason; 119 } 120 } 121 122 @Override 123 protected boolean executeTest() throws InterruptedException { 124 // Step 1: Scan and find any open network around. 125 if (DBG) Log.v(TAG, "Scan and find an open network"); 126 ScanResult openNetwork = mTestUtils.startScanAndFindAnyOpenNetworkInResults(); 127 if (openNetwork == null) { 128 setFailureReason(mContext.getString(R.string.wifi_status_scan_failure)); 129 return false; 130 } 131 132 // Step 2: Create a specifier for the chosen open network depending on the type of test. 133 NetworkSpecifier wns = createNetworkSpecifier(openNetwork); 134 if (wns == null) return false; 135 136 // Step 3: Create a network request with specifier. 137 mNetworkRequest = new NetworkRequest.Builder() 138 .addTransportType(TRANSPORT_WIFI) 139 .setNetworkSpecifier(wns) 140 .removeCapability(NET_CAPABILITY_INTERNET) 141 .build(); 142 143 // Step 4: Send the network request 144 if (DBG) Log.v(TAG, "Request network using " + mNetworkRequest); 145 mNetworkCallback = new CallbackUtils.NetworkCallback(CALLBACK_TIMEOUT_MS); 146 mListener.onTestMsgReceived( 147 mContext.getString(R.string.wifi_status_initiating_network_request)); 148 mConnectivityManager.requestNetwork(mNetworkRequest, mNetworkCallback, 149 NETWORK_REQUEST_TIMEOUT_MS); 150 151 // Step 5: Wait for the network available/unavailable callback. 152 if (mNetworkSpecifierType == NETWORK_SPECIFIER_UNAVAILABLE_SSID_BSSID) { 153 mListener.onTestMsgReceived( 154 mContext.getString(R.string.wifi_status_network_wait_for_unavailable)); 155 if (DBG) Log.v(TAG, "Waiting for network unavailable callback"); 156 boolean cbStatusForUnavailable = mNetworkCallback.waitForUnavailable(); 157 if (!cbStatusForUnavailable) { 158 Log.e(TAG, "Failed to get network unavailable callback"); 159 setFailureReason(mContext.getString(R.string.wifi_status_network_cb_timeout)); 160 return false; 161 } 162 mListener.onTestMsgReceived( 163 mContext.getString(R.string.wifi_status_network_unavailable)); 164 // All done! 165 return true; 166 } 167 mListener.onTestMsgReceived( 168 mContext.getString(R.string.wifi_status_network_wait_for_available)); 169 if (DBG) Log.v(TAG, "Waiting for network available callback"); 170 Pair<Boolean, Network> cbStatusForAvailable = mNetworkCallback.waitForAvailable(); 171 if (!cbStatusForAvailable.first) { 172 Log.e(TAG, "Failed to get network available callback"); 173 setFailureReason(mContext.getString(R.string.wifi_status_network_cb_timeout)); 174 return false; 175 } 176 mListener.onTestMsgReceived( 177 mContext.getString(R.string.wifi_status_network_available)); 178 179 mListener.onTestMsgReceived( 180 mContext.getString(R.string.wifi_status_network_wait_for_lost)); 181 // Step 6: Ensure we don't disconnect from the network as long as the request is alive. 182 if (DBG) Log.v(TAG, "Ensuring network lost callback is not invoked"); 183 boolean cbStatusForLost = mNetworkCallback.waitForLost(); 184 if (cbStatusForLost) { 185 Log.e(TAG, "Disconnected from the network even though the request is active"); 186 setFailureReason(mContext.getString(R.string.wifi_status_network_lost)); 187 return false; 188 } 189 // All done! 190 return true; 191 } 192 193 @Override 194 protected String getFailureReason() { 195 synchronized (mLock) { 196 return mFailureReason; 197 } 198 } 199 200 @Override 201 protected void setUp() { 202 super.setUp(); 203 mConnectivityManager = ConnectivityManager.from(mContext); 204 } 205 206 @Override 207 protected void tearDown() { 208 if (mNetworkCallback != null) { 209 mConnectivityManager.unregisterNetworkCallback(mNetworkCallback); 210 } 211 super.tearDown(); 212 } 213 } 214