[go: nahoru, domu]

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}