blob: 76b702ecc87bf46d6971142e5675ce7f92e3b8a3 [file] [log] [blame]
Tsu Chiang Chuang33f86992011-07-27 15:51:49 -07001/*
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;
Tsu Chiang Chuang6951b1b2011-08-17 16:21:58 -070023import android.net.NetworkStats.Entry;
Tsu Chiang Chuang33f86992011-07-27 15:51:49 -070024import 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;
Tsu Chiang Chuang6951b1b2011-08-17 16:21:58 -070039import java.util.HashMap;
40import java.util.Map;
Tsu Chiang Chuang33f86992011-07-27 15:51:49 -070041
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
Jeff Sharkey163e6442011-10-31 16:37:52 -070092 public void testWifiDownload() throws Exception {
Tsu Chiang Chuanga8c57bf2012-02-01 15:24:51 -080093 mConnectionUtil.wifiTestInit();
Tsu Chiang Chuang212efac2011-11-07 11:52:08 -080094 assertTrue("Could not connect to wifi!", setDeviceWifiAndAirplaneMode(mSsid));
95 downloadFile();
96 }
97
98 /**
99 * Ensure that downloading on mobile reports reasonable stats.
100 */
101 @LargeTest
102 public void testMobileDownload() throws Exception {
103 // As part of the setup we disconnected from wifi; make sure we are connected to mobile and
104 // that we have data.
105 assertTrue("Do not have mobile data!", hasMobileData());
106 downloadFile();
107 }
108
109 /**
110 * Helper method that downloads a file using http connection from a test server and reports the
111 * data usage stats to instrumentation out.
112 */
113 protected void downloadFile() throws Exception {
Tsu Chiang Chuang33f86992011-07-27 15:51:49 -0700114 NetworkStats pre_test_stats = fetchDataFromProc(mUid);
115 String ts = Long.toString(System.currentTimeMillis());
116
117 String targetUrl = BandwidthTestUtil.buildDownloadUrl(
118 mTestServer, FILE_SIZE, mDeviceId, ts);
119 TrafficStats.startDataProfiling(mContext);
120 File tmpSaveFile = new File(BASE_DIR + File.separator + TMP_FILENAME);
121 assertTrue(BandwidthTestUtil.DownloadFromUrl(targetUrl, tmpSaveFile));
122 NetworkStats prof_stats = TrafficStats.stopDataProfiling(mContext);
Tsu Chiang Chuang6951b1b2011-08-17 16:21:58 -0700123 Log.d(LOG_TAG, prof_stats.toString());
Tsu Chiang Chuang33f86992011-07-27 15:51:49 -0700124
125 NetworkStats post_test_stats = fetchDataFromProc(mUid);
126 NetworkStats proc_stats = post_test_stats.subtract(pre_test_stats);
127
128 // Output measurements to instrumentation out, so that it can be compared to that of
129 // the server.
130 Bundle results = new Bundle();
131 results.putString("device_id", mDeviceId);
132 results.putString("timestamp", ts);
133 results.putInt("size", FILE_SIZE);
134 AddStatsToResults(PROF_LABEL, prof_stats, results);
135 AddStatsToResults(PROC_LABEL, proc_stats, results);
136 getInstrumentation().sendStatus(INSTRUMENTATION_IN_PROGRESS, results);
137
138 // Clean up.
139 assertTrue(cleanUpFile(tmpSaveFile));
140 }
141
142 /**
Tsu Chiang Chuang212efac2011-11-07 11:52:08 -0800143 * Ensure that uploading on wifi reports reasonable stats.
Tsu Chiang Chuange8886852011-09-14 16:10:12 -0700144 */
145 @LargeTest
Jeff Sharkey163e6442011-10-31 16:37:52 -0700146 public void testWifiUpload() throws Exception {
Tsu Chiang Chuanga8c57bf2012-02-01 15:24:51 -0800147 mConnectionUtil.wifiTestInit();
Tsu Chiang Chuange8886852011-09-14 16:10:12 -0700148 assertTrue(setDeviceWifiAndAirplaneMode(mSsid));
Tsu Chiang Chuang212efac2011-11-07 11:52:08 -0800149 uploadFile();
150 }
151
152 /**
153 * Ensure that uploading on wifi reports reasonable stats.
154 */
155 @LargeTest
156 public void testMobileUpload() throws Exception {
157 assertTrue(hasMobileData());
158 uploadFile();
159 }
160
161 /**
162 * Helper method that downloads a test file to upload. The stats reported to instrumentation out
163 * only include upload stats.
164 */
165 protected void uploadFile() throws Exception {
Tsu Chiang Chuange8886852011-09-14 16:10:12 -0700166 // Download a file from the server.
167 String ts = Long.toString(System.currentTimeMillis());
168 String targetUrl = BandwidthTestUtil.buildDownloadUrl(
169 mTestServer, FILE_SIZE, mDeviceId, ts);
170 File tmpSaveFile = new File(BASE_DIR + File.separator + TMP_FILENAME);
171 assertTrue(BandwidthTestUtil.DownloadFromUrl(targetUrl, tmpSaveFile));
172
173 ts = Long.toString(System.currentTimeMillis());
174 NetworkStats pre_test_stats = fetchDataFromProc(mUid);
175 TrafficStats.startDataProfiling(mContext);
176 assertTrue(BandwidthTestUtil.postFileToServer(mTestServer, mDeviceId, ts, tmpSaveFile));
177 NetworkStats prof_stats = TrafficStats.stopDataProfiling(mContext);
178 Log.d(LOG_TAG, prof_stats.toString());
179 NetworkStats post_test_stats = fetchDataFromProc(mUid);
180 NetworkStats proc_stats = post_test_stats.subtract(pre_test_stats);
181
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 /**
Tsu Chiang Chuang212efac2011-11-07 11:52:08 -0800197 * We want to make sure that if we use wifi and the Download Manager to download stuff,
Tsu Chiang Chuang33f86992011-07-27 15:51:49 -0700198 * accounting still goes to the app making the call and that the numbers still make sense.
199 */
200 @LargeTest
Jeff Sharkey163e6442011-10-31 16:37:52 -0700201 public void testWifiDownloadWithDownloadManager() throws Exception {
Tsu Chiang Chuanga8c57bf2012-02-01 15:24:51 -0800202 mConnectionUtil.wifiTestInit();
Tsu Chiang Chuang33f86992011-07-27 15:51:49 -0700203 assertTrue(setDeviceWifiAndAirplaneMode(mSsid));
Tsu Chiang Chuang212efac2011-11-07 11:52:08 -0800204 downloadFileUsingDownloadManager();
205 }
206
207 /**
208 * We want to make sure that if we use mobile data and the Download Manager to download stuff,
209 * accounting still goes to the app making the call and that the numbers still make sense.
210 */
211 @LargeTest
212 public void testMobileDownloadWithDownloadManager() throws Exception {
213 assertTrue(hasMobileData());
214 downloadFileUsingDownloadManager();
215 }
216
217 /**
218 * Helper method that downloads a file from a test server using the download manager and reports
219 * the stats to instrumentation out.
220 */
221 protected void downloadFileUsingDownloadManager() throws Exception {
Tsu Chiang Chuang33f86992011-07-27 15:51:49 -0700222 // If we are using the download manager, then the data that is written to /proc/uid_stat/
223 // is accounted against download manager's uid, since it uses pre-ICS API.
224 int downloadManagerUid = mConnectionUtil.downloadManagerUid();
225 assertTrue(downloadManagerUid >= 0);
226 NetworkStats pre_test_stats = fetchDataFromProc(downloadManagerUid);
227 // start profiling
228 TrafficStats.startDataProfiling(mContext);
229 String ts = Long.toString(System.currentTimeMillis());
230 String targetUrl = BandwidthTestUtil.buildDownloadUrl(
231 mTestServer, FILE_SIZE, mDeviceId, ts);
232 Log.v(LOG_TAG, "Download url: " + targetUrl);
233 File tmpSaveFile = new File(BASE_DIR + File.separator + TMP_FILENAME);
234 assertTrue(mConnectionUtil.startDownloadAndWait(targetUrl, 500000));
235 NetworkStats prof_stats = TrafficStats.stopDataProfiling(mContext);
236 NetworkStats post_test_stats = fetchDataFromProc(downloadManagerUid);
237 NetworkStats proc_stats = post_test_stats.subtract(pre_test_stats);
Tsu Chiang Chuang6951b1b2011-08-17 16:21:58 -0700238 Log.d(LOG_TAG, prof_stats.toString());
Tsu Chiang Chuang33f86992011-07-27 15:51:49 -0700239 // Output measurements to instrumentation out, so that it can be compared to that of
240 // the server.
241 Bundle results = new Bundle();
242 results.putString("device_id", mDeviceId);
243 results.putString("timestamp", ts);
244 results.putInt("size", FILE_SIZE);
245 AddStatsToResults(PROF_LABEL, prof_stats, results);
246 AddStatsToResults(PROC_LABEL, proc_stats, results);
247 getInstrumentation().sendStatus(INSTRUMENTATION_IN_PROGRESS, results);
248
249 // Clean up.
250 assertTrue(cleanUpFile(tmpSaveFile));
251 }
252
253 /**
254 * Fetch network data from /proc/uid_stat/uid
Tsu Chiang Chuang212efac2011-11-07 11:52:08 -0800255 *
Tsu Chiang Chuang33f86992011-07-27 15:51:49 -0700256 * @return populated {@link NetworkStats}
257 */
258 public NetworkStats fetchDataFromProc(int uid) {
259 String root_filepath = "/proc/uid_stat/" + uid + "/";
260 File rcv_stat = new File (root_filepath + "tcp_rcv");
261 int rx = BandwidthTestUtil.parseIntValueFromFile(rcv_stat);
262 File snd_stat = new File (root_filepath + "tcp_snd");
263 int tx = BandwidthTestUtil.parseIntValueFromFile(snd_stat);
264 NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700265 stats.addValues(NetworkStats.IFACE_ALL, uid, NetworkStats.SET_DEFAULT,
266 NetworkStats.TAG_NONE, rx, 0, tx, 0, 0);
Tsu Chiang Chuang33f86992011-07-27 15:51:49 -0700267 return stats;
268 }
269
270 /**
Tsu Chiang Chuang212efac2011-11-07 11:52:08 -0800271 * Turn on Airplane mode and connect to the wifi.
272 *
Tsu Chiang Chuang33f86992011-07-27 15:51:49 -0700273 * @param ssid of the wifi to connect to
274 * @return true if we successfully connected to a given network.
275 */
276 public boolean setDeviceWifiAndAirplaneMode(String ssid) {
277 mConnectionUtil.setAirplaneMode(mContext, true);
278 assertTrue(mConnectionUtil.connectToWifi(ssid));
279 assertTrue(mConnectionUtil.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
280 ConnectionUtil.LONG_TIMEOUT));
Tsu Chiang Chuang212efac2011-11-07 11:52:08 -0800281 assertTrue(mConnectionUtil.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
282 State.CONNECTED, ConnectionUtil.LONG_TIMEOUT));
283 return mConnectionUtil.hasData();
284 }
285
286 /**
287 * Helper method to make sure we are connected to mobile data.
288 *
289 * @return true if we successfully connect to mobile data.
290 */
291 public boolean hasMobileData() {
Tsu Chiang Chuanga8c57bf2012-02-01 15:24:51 -0800292 assertTrue(mConnectionUtil.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
293 State.CONNECTED, ConnectionUtil.LONG_TIMEOUT));
Tsu Chiang Chuang212efac2011-11-07 11:52:08 -0800294 assertTrue("Not connected to mobile", mConnectionUtil.isConnectedToMobile());
295 assertFalse("Still connected to wifi.", mConnectionUtil.isConnectedToWifi());
296 return mConnectionUtil.hasData();
Tsu Chiang Chuang33f86992011-07-27 15:51:49 -0700297 }
298
299 /**
300 * Output the {@link NetworkStats} to Instrumentation out.
Tsu Chiang Chuang212efac2011-11-07 11:52:08 -0800301 *
Tsu Chiang Chuang33f86992011-07-27 15:51:49 -0700302 * @param label to attach to this given stats.
303 * @param stats {@link NetworkStats} to add.
304 * @param results {@link Bundle} to be added to.
305 */
306 public void AddStatsToResults(String label, NetworkStats stats, Bundle results){
307 if (results == null || results.isEmpty()) {
308 Log.e(LOG_TAG, "Empty bundle provided.");
309 return;
310 }
Tsu Chiang Chuang6951b1b2011-08-17 16:21:58 -0700311 // Merge stats across all sets.
312 Map<Integer, Entry> totalStats = new HashMap<Integer, Entry>();
Tsu Chiang Chuang33f86992011-07-27 15:51:49 -0700313 for (int i = 0; i < stats.size(); ++i) {
Tsu Chiang Chuang6951b1b2011-08-17 16:21:58 -0700314 Entry statsEntry = stats.getValues(i, null);
315 // We are only interested in the all inclusive stats.
316 if (statsEntry.tag != 0) {
317 continue;
318 }
319 Entry mapEntry = null;
320 if (totalStats.containsKey(statsEntry.uid)) {
321 mapEntry = totalStats.get(statsEntry.uid);
322 switch (statsEntry.set) {
323 case NetworkStats.SET_ALL:
324 mapEntry.rxBytes = statsEntry.rxBytes;
325 mapEntry.txBytes = statsEntry.txBytes;
326 break;
327 case NetworkStats.SET_DEFAULT:
328 case NetworkStats.SET_FOREGROUND:
329 mapEntry.rxBytes += statsEntry.rxBytes;
330 mapEntry.txBytes += statsEntry.txBytes;
331 break;
332 default:
333 Log.w(LOG_TAG, "Invalid state found in NetworkStats.");
334 }
335 } else {
336 totalStats.put(statsEntry.uid, statsEntry);
337 }
338 }
339 // Ouput merged stats to bundle.
340 for (Entry entry : totalStats.values()) {
Tsu Chiang Chuang33f86992011-07-27 15:51:49 -0700341 results.putInt(label + "uid", entry.uid);
Tsu Chiang Chuang33f86992011-07-27 15:51:49 -0700342 results.putLong(label + "tx", entry.txBytes);
343 results.putLong(label + "rx", entry.rxBytes);
344 }
345 }
346
347 /**
348 * Remove file if it exists.
349 * @param file {@link File} to delete.
350 * @return true if successfully deleted the file.
351 */
352 private boolean cleanUpFile(File file) {
353 if (file.exists()) {
354 return file.delete();
355 }
356 return true;
357 }
Tsu Chiang Chuang287353a2011-11-10 10:13:14 -0800358}