Add NetworkUsageStatsTest to CTS suite
Bug: 19572685
Change-Id: Ie390464ca27ace87f625ec7c5e884c5b0b333fa2
diff --git a/tests/tests/app.usage/AndroidManifest.xml b/tests/tests/app.usage/AndroidManifest.xml
index 11065d4..3bd795a 100644
--- a/tests/tests/app.usage/AndroidManifest.xml
+++ b/tests/tests/app.usage/AndroidManifest.xml
@@ -21,6 +21,9 @@
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
<uses-permission android:name="android.permission.SET_TIME" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java b/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
new file mode 100644
index 0000000..c3ba834
--- /dev/null
+++ b/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
@@ -0,0 +1,339 @@
+/**
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package android.app.usage.cts;
+
+import android.app.AppOpsManager;
+import android.app.usage.NetworkStatsManager;
+import android.app.usage.NetworkStats;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.LocalServerSocket;
+import android.net.LocalSocket;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.net.NetworkRequest;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.RemoteException;
+import android.test.InstrumentationTestCase;
+import android.util.Log;
+
+import dalvik.system.SocketTagger;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.ServerSocket;
+import java.net.URL;
+import java.text.MessageFormat;
+import javax.net.ssl.HttpsURLConnection;
+
+import libcore.io.IoUtils;
+import libcore.io.Streams;
+
+public class NetworkUsageStatsTest extends InstrumentationTestCase {
+ private static final String LOG_TAG = "NetworkUsageStatsTest";
+ private static final String APPOPS_SET_SHELL_COMMAND = "appops set {0} " +
+ AppOpsManager.OPSTR_GET_USAGE_STATS + " {1}";
+
+ private static final long MINUTE = 1000 * 60;
+
+ private static final int[] sNetworkTypesToTest = new int[] {
+ ConnectivityManager.TYPE_WIFI,
+ ConnectivityManager.TYPE_MOBILE,
+ };
+
+ // Order corresponds to sNetworkTypesToTest
+ private static final int[] sTransportTypesToTest = new int[] {
+ NetworkCapabilities.TRANSPORT_WIFI,
+ NetworkCapabilities.TRANSPORT_CELLULAR,
+ };
+
+ private NetworkStatsManager mNsm;
+ private PackageManager mPm;
+ private ConnectivityManager mCm;
+ private long mStartTime;
+ private long mEndTime;
+
+ private long mBytesRead;
+
+ private void exerciseRemoteHost(int transportType) throws Exception {
+ final int timeout = 60000;
+ mCm.requestNetwork(new NetworkRequest.Builder()
+ .addTransportType(transportType)
+ .build(), new ConnectivityManager.NetworkCallback() {
+ @Override
+ public void onAvailable(Network network) {
+ NetworkInfo networkInfo = mCm.getNetworkInfo(network);
+ if (networkInfo == null) {
+ Log.w(LOG_TAG, "Network info is null");
+ } else {
+ Log.w(LOG_TAG, "Network: " + networkInfo.toString());
+ }
+ InputStreamReader in = null;
+ HttpsURLConnection urlc = null;
+ String originalKeepAlive = System.getProperty("http.keepAlive");
+ System.setProperty("http.keepAlive", "false");
+ try {
+ urlc = (HttpsURLConnection) network.openConnection(new URL(
+ "https://www.google.com"));
+ urlc.setConnectTimeout(timeout);
+ urlc.setUseCaches(false);
+ urlc.connect();
+ boolean ping = urlc.getResponseCode() == 200;
+ if (ping) {
+ in = new InputStreamReader(
+ (InputStream) urlc.getContent());
+
+ mBytesRead = 0;
+ while (in.read() != -1) ++mBytesRead;
+ }
+ } catch (Exception e) {
+ Log.i(LOG_TAG, "Badness during exercising remote server: " + e);
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ // don't care
+ }
+ }
+ if (urlc != null) {
+ urlc.disconnect();
+ }
+ if (originalKeepAlive == null) {
+ System.clearProperty("http.keepAlive");
+ } else {
+ System.setProperty("http.keepAlive", originalKeepAlive);
+ }
+ }
+ }
+ });
+ try {
+ Thread.sleep(timeout);
+ } catch (InterruptedException e) {
+ }
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ mNsm = (NetworkStatsManager) getInstrumentation().getContext()
+ .getSystemService(Context.NETWORK_STATS_SERVICE);
+
+ mPm = getInstrumentation().getContext().getPackageManager();
+ mCm = (ConnectivityManager) getInstrumentation().getContext()
+ .getSystemService(Context.CONNECTIVITY_SERVICE);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ private void setAppOpsMode(String mode) throws Exception {
+ final String command = MessageFormat.format(APPOPS_SET_SHELL_COMMAND,
+ getInstrumentation().getContext().getPackageName(), mode);
+ ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation()
+ .executeShellCommand(command);
+ try {
+ Streams.readFully(new FileInputStream(pfd.getFileDescriptor()));
+ } finally {
+ IoUtils.closeQuietly(pfd.getFileDescriptor());
+ }
+ }
+
+ private boolean shouldTestThisNetworkType(int networkTypeIndex) throws Exception {
+ NetworkInfo networkInfo = mCm.getNetworkInfo(sNetworkTypesToTest[networkTypeIndex]);
+ if (networkInfo == null || !networkInfo.isAvailable()) {
+ return false;
+ }
+ mStartTime = System.currentTimeMillis() - MINUTE/2;
+ exerciseRemoteHost(sTransportTypesToTest[networkTypeIndex]);
+ mEndTime = System.currentTimeMillis() + MINUTE/2;
+ return true;
+ }
+
+ public void testDeviceSummary() throws Exception {
+ for (int i = 0; i < sNetworkTypesToTest.length; ++i) {
+ if (!shouldTestThisNetworkType(i)) {
+ continue;
+ }
+ setAppOpsMode("allow");
+ NetworkStats.Bucket bucket = null;
+ try {
+ bucket = mNsm.querySummaryForDevice(
+ sNetworkTypesToTest[i], "", mStartTime, mEndTime);
+ } catch (RemoteException | SecurityException e) {
+ fail("testDeviceSummary fails with exception: " + e.toString());
+ }
+ assertTrue(bucket != null);
+ setAppOpsMode("deny");
+ try {
+ bucket = mNsm.querySummaryForDevice(
+ ConnectivityManager.TYPE_WIFI, "", mStartTime, mEndTime);
+ fail("negative testDeviceSummary fails: no exception thrown.");
+ } catch (RemoteException e) {
+ fail("testDeviceSummary fails with exception: " + e.toString());
+ } catch (SecurityException e) {
+ // expected outcome
+ }
+ }
+ }
+
+ public void testUserSummary() throws Exception {
+ for (int i = 0; i < sNetworkTypesToTest.length; ++i) {
+ if (!shouldTestThisNetworkType(i)) {
+ continue;
+ }
+ setAppOpsMode("allow");
+ NetworkStats.Bucket bucket = null;
+ try {
+ bucket = mNsm.querySummaryForUser(
+ sNetworkTypesToTest[i], "", mStartTime, mEndTime);
+ } catch (RemoteException | SecurityException e) {
+ fail("testUserSummary fails with exception: " + e.toString());
+ }
+ assertTrue(bucket != null);
+ setAppOpsMode("deny");
+ try {
+ bucket = mNsm.querySummaryForUser(
+ ConnectivityManager.TYPE_WIFI, "", mStartTime, mEndTime);
+ fail("negative testUserSummary fails: no exception thrown.");
+ } catch (RemoteException e) {
+ fail("testUserSummary fails with exception: " + e.toString());
+ } catch (SecurityException e) {
+ // expected outcome
+ }
+ }
+ }
+
+ public void testAppSummary() throws Exception {
+ for (int i = 0; i < sNetworkTypesToTest.length; ++i) {
+ if (!shouldTestThisNetworkType(i)) {
+ continue;
+ }
+ setAppOpsMode("allow");
+ NetworkStats result = null;
+ try {
+ result = mNsm.querySummary(
+ sNetworkTypesToTest[i], "", mStartTime, mEndTime);
+ assertTrue(result != null);
+ NetworkStats.Bucket bucket = new NetworkStats.Bucket();
+ long totalTxPackets = 0;
+ long totalRxPackets = 0;
+ long totalTxBytes = 0;
+ long totalRxBytes = 0;
+ while (result.getNextBucket(bucket)) {
+ if (bucket.getUid() == Process.myUid()) {
+ totalTxPackets += bucket.getTxPackets();
+ totalRxPackets += bucket.getRxPackets();
+ totalTxBytes += bucket.getTxBytes();
+ totalRxBytes += bucket.getRxBytes();
+ }
+ }
+ assertTrue("No Rx bytes usage for uid " + Process.myUid(), totalRxBytes > 0);
+ assertTrue("No Rx packets usage for uid " + Process.myUid(), totalRxPackets > 0);
+ assertTrue("No Tx bytes usage for uid " + Process.myUid(), totalTxBytes > 0);
+ assertTrue("No Tx packets usage for uid " + Process.myUid(), totalTxPackets > 0);
+ } catch (RemoteException | SecurityException e) {
+ fail("testAppSummary fails with exception: " + e.toString());
+ } finally {
+ if (result != null) {
+ result.close();
+ }
+ }
+ setAppOpsMode("deny");
+ try {
+ result = mNsm.querySummary(
+ ConnectivityManager.TYPE_WIFI, "", mStartTime, mEndTime);
+ fail("negative testAppSummary fails: no exception thrown.");
+ } catch (RemoteException e) {
+ fail("testAppSummary fails with exception: " + e.toString());
+ } catch (SecurityException e) {
+ // expected outcome
+ }
+ }
+ }
+
+ public void testAppDetails() throws Exception {
+ for (int i = 0; i < sNetworkTypesToTest.length; ++i) {
+ if (!shouldTestThisNetworkType(i)) {
+ continue;
+ }
+ setAppOpsMode("allow");
+ NetworkStats result = null;
+ try {
+ result = mNsm.queryDetails(
+ sNetworkTypesToTest[i], "", mStartTime, mEndTime);
+ assertTrue(result != null);
+ } catch (RemoteException | SecurityException e) {
+ fail("testAppDetails fails with exception: " + e.toString());
+ } finally {
+ if (result != null) {
+ result.close();
+ }
+ }
+ setAppOpsMode("deny");
+ try {
+ result = mNsm.queryDetails(
+ ConnectivityManager.TYPE_WIFI, "", mStartTime, mEndTime);
+ fail("negative testAppDetails fails: no exception thrown.");
+ } catch (RemoteException e) {
+ fail("testAppDetails fails with exception: " + e.toString());
+ } catch (SecurityException e) {
+ // expected outcome
+ }
+ }
+ }
+
+ public void testUidDetails() throws Exception {
+ for (int i = 0; i < sNetworkTypesToTest.length; ++i) {
+ if (!shouldTestThisNetworkType(i)) {
+ continue;
+ }
+ setAppOpsMode("allow");
+ NetworkStats result = null;
+ try {
+ result = mNsm.queryDetailsForUid(
+ sNetworkTypesToTest[i], "", mStartTime, mEndTime, Process.myUid());
+ assertTrue(result != null);
+ } catch (RemoteException | SecurityException e) {
+ fail("testUidDetails fails with exception: " + e.toString());
+ } finally {
+ if (result != null) {
+ result.close();
+ }
+ }
+ setAppOpsMode("deny");
+ try {
+ result = mNsm.queryDetailsForUid(
+ ConnectivityManager.TYPE_WIFI, "", mStartTime, mEndTime, Process.myUid());
+ fail("negative testUidDetails fails: no exception thrown.");
+ } catch (RemoteException e) {
+ fail("testUidDetails fails with exception: " + e.toString());
+ } catch (SecurityException e) {
+ // expected outcome
+ }
+ }
+ }
+}