BandwidthTest.java revision 163e6443f27884a9bfcb9a48ef606dc635852c23
1/* 2 * Copyright (C) 2011, 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 17package com.android.bandwidthtest; 18 19import android.content.Context; 20import android.net.ConnectivityManager; 21import android.net.NetworkInfo.State; 22import android.net.NetworkStats; 23import android.net.NetworkStats.Entry; 24import android.net.TrafficStats; 25import android.net.wifi.WifiManager; 26import android.os.Bundle; 27import android.os.Environment; 28import android.os.Process; 29import android.os.SystemClock; 30import android.telephony.TelephonyManager; 31import android.test.InstrumentationTestCase; 32import android.test.suitebuilder.annotation.LargeTest; 33import android.util.Log; 34 35import com.android.bandwidthtest.util.BandwidthTestUtil; 36import com.android.bandwidthtest.util.ConnectionUtil; 37 38import java.io.File; 39import java.util.HashMap; 40import java.util.Map; 41 42/** 43 * Test that downloads files from a test server and reports the bandwidth metrics collected. 44 */ 45public class BandwidthTest extends InstrumentationTestCase { 46 47 private static final String LOG_TAG = "BandwidthTest"; 48 private final static String PROF_LABEL = "PROF_"; 49 private final static String PROC_LABEL = "PROC_"; 50 private final static int INSTRUMENTATION_IN_PROGRESS = 2; 51 52 private final static String BASE_DIR = 53 Environment.getExternalStorageDirectory().getAbsolutePath(); 54 private final static String TMP_FILENAME = "tmp.dat"; 55 // Download 10.486 * 106 bytes (+ headers) from app engine test server. 56 private final int FILE_SIZE = 10485613; 57 private Context mContext; 58 private ConnectionUtil mConnectionUtil; 59 private TelephonyManager mTManager; 60 private int mUid; 61 private String mSsid; 62 private String mTestServer; 63 private String mDeviceId; 64 private BandwidthTestRunner mRunner; 65 66 67 @Override 68 protected void setUp() throws Exception { 69 super.setUp(); 70 mRunner = (BandwidthTestRunner) getInstrumentation(); 71 mSsid = mRunner.mSsid; 72 mTestServer = mRunner.mTestServer; 73 mContext = mRunner.getTargetContext(); 74 mConnectionUtil = new ConnectionUtil(mContext); 75 mConnectionUtil.initialize(); 76 Log.v(LOG_TAG, "Initialized mConnectionUtil"); 77 mUid = Process.myUid(); 78 mTManager = (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE); 79 mDeviceId = mTManager.getDeviceId(); 80 } 81 82 @Override 83 protected void tearDown() throws Exception { 84 mConnectionUtil.cleanUp(); 85 super.tearDown(); 86 } 87 88 /** 89 * Ensure that downloading on wifi reports reasonable stats. 90 */ 91 @LargeTest 92 public void testWifiDownload() throws Exception { 93 assertTrue(setDeviceWifiAndAirplaneMode(mSsid)); 94 NetworkStats pre_test_stats = fetchDataFromProc(mUid); 95 String ts = Long.toString(System.currentTimeMillis()); 96 97 String targetUrl = BandwidthTestUtil.buildDownloadUrl( 98 mTestServer, FILE_SIZE, mDeviceId, ts); 99 TrafficStats.startDataProfiling(mContext); 100 File tmpSaveFile = new File(BASE_DIR + File.separator + TMP_FILENAME); 101 assertTrue(BandwidthTestUtil.DownloadFromUrl(targetUrl, tmpSaveFile)); 102 NetworkStats prof_stats = TrafficStats.stopDataProfiling(mContext); 103 Log.d(LOG_TAG, prof_stats.toString()); 104 105 NetworkStats post_test_stats = fetchDataFromProc(mUid); 106 NetworkStats proc_stats = post_test_stats.subtract(pre_test_stats); 107 108 // Output measurements to instrumentation out, so that it can be compared to that of 109 // the server. 110 Bundle results = new Bundle(); 111 results.putString("device_id", mDeviceId); 112 results.putString("timestamp", ts); 113 results.putInt("size", FILE_SIZE); 114 AddStatsToResults(PROF_LABEL, prof_stats, results); 115 AddStatsToResults(PROC_LABEL, proc_stats, results); 116 getInstrumentation().sendStatus(INSTRUMENTATION_IN_PROGRESS, results); 117 118 // Clean up. 119 assertTrue(cleanUpFile(tmpSaveFile)); 120 } 121 122 /** 123 * Ensure that downloading on wifi reports reasonable stats. 124 */ 125 @LargeTest 126 public void testWifiUpload() throws Exception { 127 assertTrue(setDeviceWifiAndAirplaneMode(mSsid)); 128 // Download a file from the server. 129 String ts = Long.toString(System.currentTimeMillis()); 130 String targetUrl = BandwidthTestUtil.buildDownloadUrl( 131 mTestServer, FILE_SIZE, mDeviceId, ts); 132 File tmpSaveFile = new File(BASE_DIR + File.separator + TMP_FILENAME); 133 assertTrue(BandwidthTestUtil.DownloadFromUrl(targetUrl, tmpSaveFile)); 134 135 ts = Long.toString(System.currentTimeMillis()); 136 NetworkStats pre_test_stats = fetchDataFromProc(mUid); 137 TrafficStats.startDataProfiling(mContext); 138 assertTrue(BandwidthTestUtil.postFileToServer(mTestServer, mDeviceId, ts, tmpSaveFile)); 139 NetworkStats prof_stats = TrafficStats.stopDataProfiling(mContext); 140 Log.d(LOG_TAG, prof_stats.toString()); 141 NetworkStats post_test_stats = fetchDataFromProc(mUid); 142 NetworkStats proc_stats = post_test_stats.subtract(pre_test_stats); 143 144 // Output measurements to instrumentation out, so that it can be compared to that of 145 // the server. 146 Bundle results = new Bundle(); 147 results.putString("device_id", mDeviceId); 148 results.putString("timestamp", ts); 149 results.putInt("size", FILE_SIZE); 150 AddStatsToResults(PROF_LABEL, prof_stats, results); 151 AddStatsToResults(PROC_LABEL, proc_stats, results); 152 getInstrumentation().sendStatus(INSTRUMENTATION_IN_PROGRESS, results); 153 154 // Clean up. 155 assertTrue(cleanUpFile(tmpSaveFile)); 156 } 157 158 /** 159 * We want to make sure that if we use the Download Manager to download stuff, 160 * accounting still goes to the app making the call and that the numbers still make sense. 161 */ 162 @LargeTest 163 public void testWifiDownloadWithDownloadManager() throws Exception { 164 assertTrue(setDeviceWifiAndAirplaneMode(mSsid)); 165 // If we are using the download manager, then the data that is written to /proc/uid_stat/ 166 // is accounted against download manager's uid, since it uses pre-ICS API. 167 int downloadManagerUid = mConnectionUtil.downloadManagerUid(); 168 assertTrue(downloadManagerUid >= 0); 169 NetworkStats pre_test_stats = fetchDataFromProc(downloadManagerUid); 170 // start profiling 171 TrafficStats.startDataProfiling(mContext); 172 String ts = Long.toString(System.currentTimeMillis()); 173 String targetUrl = BandwidthTestUtil.buildDownloadUrl( 174 mTestServer, FILE_SIZE, mDeviceId, ts); 175 Log.v(LOG_TAG, "Download url: " + targetUrl); 176 File tmpSaveFile = new File(BASE_DIR + File.separator + TMP_FILENAME); 177 assertTrue(mConnectionUtil.startDownloadAndWait(targetUrl, 500000)); 178 NetworkStats prof_stats = TrafficStats.stopDataProfiling(mContext); 179 NetworkStats post_test_stats = fetchDataFromProc(downloadManagerUid); 180 NetworkStats proc_stats = post_test_stats.subtract(pre_test_stats); 181 Log.d(LOG_TAG, prof_stats.toString()); 182 // Output measurements to instrumentation out, so that it can be compared to that of 183 // the server. 184 Bundle results = new Bundle(); 185 results.putString("device_id", mDeviceId); 186 results.putString("timestamp", ts); 187 results.putInt("size", FILE_SIZE); 188 AddStatsToResults(PROF_LABEL, prof_stats, results); 189 AddStatsToResults(PROC_LABEL, proc_stats, results); 190 getInstrumentation().sendStatus(INSTRUMENTATION_IN_PROGRESS, results); 191 192 // Clean up. 193 assertTrue(cleanUpFile(tmpSaveFile)); 194 } 195 196 /** 197 * Fetch network data from /proc/uid_stat/uid 198 * @return populated {@link NetworkStats} 199 */ 200 public NetworkStats fetchDataFromProc(int uid) { 201 String root_filepath = "/proc/uid_stat/" + uid + "/"; 202 File rcv_stat = new File (root_filepath + "tcp_rcv"); 203 int rx = BandwidthTestUtil.parseIntValueFromFile(rcv_stat); 204 File snd_stat = new File (root_filepath + "tcp_snd"); 205 int tx = BandwidthTestUtil.parseIntValueFromFile(snd_stat); 206 NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1); 207 stats.addValues(NetworkStats.IFACE_ALL, uid, NetworkStats.SET_DEFAULT, 208 NetworkStats.TAG_NONE, rx, 0, tx, 0, 0); 209 return stats; 210 } 211 212 /** 213 * Turn on Airplane mode and connect to the wifi 214 * @param ssid of the wifi to connect to 215 * @return true if we successfully connected to a given network. 216 */ 217 public boolean setDeviceWifiAndAirplaneMode(String ssid) { 218 mConnectionUtil.setAirplaneMode(mContext, true); 219 assertTrue(mConnectionUtil.connectToWifi(ssid)); 220 assertTrue(mConnectionUtil.waitForWifiState(WifiManager.WIFI_STATE_ENABLED, 221 ConnectionUtil.LONG_TIMEOUT)); 222 return mConnectionUtil.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED, 223 ConnectionUtil.LONG_TIMEOUT); 224 } 225 226 /** 227 * Output the {@link NetworkStats} to Instrumentation out. 228 * @param label to attach to this given stats. 229 * @param stats {@link NetworkStats} to add. 230 * @param results {@link Bundle} to be added to. 231 */ 232 public void AddStatsToResults(String label, NetworkStats stats, Bundle results){ 233 if (results == null || results.isEmpty()) { 234 Log.e(LOG_TAG, "Empty bundle provided."); 235 return; 236 } 237 // Merge stats across all sets. 238 Map<Integer, Entry> totalStats = new HashMap<Integer, Entry>(); 239 for (int i = 0; i < stats.size(); ++i) { 240 Entry statsEntry = stats.getValues(i, null); 241 // We are only interested in the all inclusive stats. 242 if (statsEntry.tag != 0) { 243 continue; 244 } 245 Entry mapEntry = null; 246 if (totalStats.containsKey(statsEntry.uid)) { 247 mapEntry = totalStats.get(statsEntry.uid); 248 switch (statsEntry.set) { 249 case NetworkStats.SET_ALL: 250 mapEntry.rxBytes = statsEntry.rxBytes; 251 mapEntry.txBytes = statsEntry.txBytes; 252 break; 253 case NetworkStats.SET_DEFAULT: 254 case NetworkStats.SET_FOREGROUND: 255 mapEntry.rxBytes += statsEntry.rxBytes; 256 mapEntry.txBytes += statsEntry.txBytes; 257 break; 258 default: 259 Log.w(LOG_TAG, "Invalid state found in NetworkStats."); 260 } 261 } else { 262 totalStats.put(statsEntry.uid, statsEntry); 263 } 264 } 265 // Ouput merged stats to bundle. 266 for (Entry entry : totalStats.values()) { 267 results.putInt(label + "uid", entry.uid); 268 results.putLong(label + "tx", entry.txBytes); 269 results.putLong(label + "rx", entry.rxBytes); 270 } 271 } 272 273 /** 274 * Remove file if it exists. 275 * @param file {@link File} to delete. 276 * @return true if successfully deleted the file. 277 */ 278 private boolean cleanUpFile(File file) { 279 if (file.exists()) { 280 return file.delete(); 281 } 282 return true; 283 } 284}