Merge "Add test for internet availability on portals" into rvc-dev
diff --git a/tests/cts/net/src/android/net/cts/NetworkStatsBinderTest.java b/tests/cts/net/src/android/net/cts/NetworkStatsBinderTest.java
new file mode 100644
index 0000000..1f3162f
--- /dev/null
+++ b/tests/cts/net/src/android/net/cts/NetworkStatsBinderTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2020 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.net.cts;
+
+import static android.os.Process.INVALID_UID;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.net.INetworkStatsService;
+import android.net.TrafficStats;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.test.AndroidTestCase;
+import android.util.SparseArray;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.internal.util.CollectionUtils;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+public class NetworkStatsBinderTest extends AndroidTestCase {
+ // NOTE: These are shamelessly copied from TrafficStats.
+ private static final int TYPE_RX_BYTES = 0;
+ private static final int TYPE_RX_PACKETS = 1;
+ private static final int TYPE_TX_BYTES = 2;
+ private static final int TYPE_TX_PACKETS = 3;
+
+ private final SparseArray<Function<Integer, Long>> mUidStatsQueryOpArray = new SparseArray<>();
+
+ @Override
+ protected void setUp() throws Exception {
+ mUidStatsQueryOpArray.put(TYPE_RX_BYTES, uid -> TrafficStats.getUidRxBytes(uid));
+ mUidStatsQueryOpArray.put(TYPE_RX_PACKETS, uid -> TrafficStats.getUidRxPackets(uid));
+ mUidStatsQueryOpArray.put(TYPE_TX_BYTES, uid -> TrafficStats.getUidTxBytes(uid));
+ mUidStatsQueryOpArray.put(TYPE_TX_PACKETS, uid -> TrafficStats.getUidTxPackets(uid));
+ }
+
+ private long getUidStatsFromBinder(int uid, int type) throws Exception {
+ Method getServiceMethod = Class.forName("android.os.ServiceManager")
+ .getDeclaredMethod("getService", new Class[]{String.class});
+ IBinder binder = (IBinder) getServiceMethod.invoke(null, Context.NETWORK_STATS_SERVICE);
+ INetworkStatsService nss = INetworkStatsService.Stub.asInterface(binder);
+ return nss.getUidStats(uid, type);
+ }
+
+ private int getFirstAppUidThat(@NonNull Predicate<Integer> predicate) {
+ PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
+ List<PackageInfo> apps = pm.getInstalledPackages(0 /* flags */);
+ final PackageInfo match = CollectionUtils.find(apps,
+ it -> it.applicationInfo != null && predicate.test(it.applicationInfo.uid));
+ if (match != null) return match.applicationInfo.uid;
+ return INVALID_UID;
+ }
+
+ public void testAccessUidStatsFromBinder() throws Exception {
+ final int myUid = Process.myUid();
+ final List<Integer> testUidList = new ArrayList<>();
+
+ // Prepare uid list for testing.
+ testUidList.add(INVALID_UID);
+ testUidList.add(Process.ROOT_UID);
+ testUidList.add(Process.SYSTEM_UID);
+ testUidList.add(myUid);
+ testUidList.add(Process.LAST_APPLICATION_UID);
+ testUidList.add(Process.LAST_APPLICATION_UID + 1);
+ // If available, pick another existing uid for testing that is not already contained
+ // in the list above.
+ final int notMyUid = getFirstAppUidThat(uid -> uid >= 0 && !testUidList.contains(uid));
+ if (notMyUid != INVALID_UID) testUidList.add(notMyUid);
+
+ for (final int uid : testUidList) {
+ for (int i = 0; i < mUidStatsQueryOpArray.size(); i++) {
+ final int type = mUidStatsQueryOpArray.keyAt(i);
+ try {
+ final long uidStatsFromBinder = getUidStatsFromBinder(uid, type);
+ final long uidTrafficStats = mUidStatsQueryOpArray.get(type).apply(uid);
+
+ // Verify that UNSUPPORTED is returned if the uid is not current app uid.
+ if (uid != myUid) {
+ assertEquals(uidStatsFromBinder, TrafficStats.UNSUPPORTED);
+ }
+ // Verify that returned result is the same with the result get from
+ // TrafficStats.
+ // TODO: If the test is flaky then it should instead assert that the values
+ // are approximately similar.
+ assertEquals("uidStats is not matched for query type " + type
+ + ", uid=" + uid + ", myUid=" + myUid, uidTrafficStats,
+ uidStatsFromBinder);
+ } catch (IllegalAccessException e) {
+ /* Java language access prevents exploitation. */
+ return;
+ } catch (InvocationTargetException e) {
+ /* Underlying method has been changed. */
+ return;
+ } catch (ClassNotFoundException e) {
+ /* not vulnerable if hidden API no longer available */
+ return;
+ } catch (NoSuchMethodException e) {
+ /* not vulnerable if hidden API no longer available */
+ return;
+ } catch (RemoteException e) {
+ return;
+ }
+ }
+ }
+ }
+}
diff --git a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
index 6214f89..824146f 100644
--- a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
+++ b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
@@ -16,6 +16,7 @@
package android.net.cts.util;
+import static android.Manifest.permission.NETWORK_SETTINGS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -107,6 +108,8 @@
boolean connected = false;
try {
SystemUtil.runShellCommand("svc wifi enable");
+ SystemUtil.runWithShellPermissionIdentity(() -> mWifiManager.reconnect(),
+ NETWORK_SETTINGS);
// Ensure we get both an onAvailable callback and a CONNECTIVITY_ACTION.
wifiNetwork = callback.waitForAvailable();
assertNotNull(wifiNetwork);